相关的背景知识
TCP是面向建立连接的协议,运输连接是用来传送TCP报文的,TCP运输连接的建立和释放是每一次面向连接通信必不可少的过程,运输连接有三个过程:连接建立,数据传送和连接释放。
在TCP连接建立的过程主要解决一下的问题:
1)要使每一方都能确知对方的存在;
2)要允许双方协商一些参数(如最大窗口值、是否使用窗口扩大选项和时间戳选项以及服务的质量等);
3)能够对运输实体资源(如缓存的大小、连接表中的项目等)进行分配;
TCP建立连接的过程中采用客户服务器方式,主动发起连接建立的应用进程叫做客户,而被动等待建立连接的应用进程叫做服务器);
TCP的6个标志位
URG:紧急指针是否有效
ACK:确认号是否有效
PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走;
RST:对方要求重新建立连接,我们把携带RST标识称为复位报文段
SYN:请求建立连接;我们把携带SYN标识的称为同步报文段
FIN:通知对方,本端要关闭了,我们称携带FIN标识的为结束报文段
三次握手
通常情况下TCP都要经过三次挥手建立连接,四次握手释放连接。
这里写图片描述
TCP的报头信息:
这里写图片描述
三次握手的过程:
客户端发起建立请求的过程,向服务器发送一个SYN希望建立连接,并消耗一个序列号。
- 服务器收到客户端的请求之后,如果能够同意建立连接,则会向客户端返回一个SYN+ACK,表示确认应答。
- 客户端在收到应答之后,向服务器发送一个请求应答ACK,确认自己已经应答。
服务器在三次握手的过程当中发生的变化:
起初,服务器和客户端都是处于CLOSED(关闭)状态。B的TCP服务器进程先创建传输控制块TCB,准备接受客户进程的连接请求,然后服务器进程就处于LISTEN(收听)状态,等待客户的连接请求。如有,立即就会做出响应的。
一旦接到连接请求之后,就将该连接放入到内核的等待队列当中去,状态就变为了SYN-RCVD(同步接收)。
服务器在接收到客户端的确认之后,就进入了ESTABILSHED状态。
客户端状态的变化:
客户端想服务器发送SYN同步报文段,从CLOSED状态就变化为SYN_SENT同步发送状态。
客户端在向服务器发送ACK确认应答之后,就变成了ESTABLISHED状态,当双方都变成了这种状态就说明连接已经建立,两者之间就可以进行数据数据读写通信了。
为什么TCP是三次握手,而不是两次或者四次呢?
2次握手:客户端向服务器发送SYN希望建立连接,服务器向客户端发送SYN+ACK表示确认应答。但是如果在服务器回应的过程中,ACK丢失的话,那么客户就会认为连接是建立失败了,因为没有收到服务器的确认应答,但是服务器确认为连接已经进行建立了,因为他认为自己收到了服务器的确认应答ACK和返回SYN,这样造成双方出现认知不一致的问题。那么客户端就会重复的进行发送请求,服务器在收到连接请求的时候,会为该连接分配资源,同时创建数据结构进行维护,所以在出现ACK丢失的问题,服务器就会为认为已经建立好的连接消耗很多的资源,但这些资源都属于无效的资源,那么可用的资源就会变得非常的少。
四次握手:如果三次握手就已经足够了,就不需要进行四次握手了,在四次握手的过程中,如果ACK进行丢失的话也会出现两次握手的问题,造成资源的浪费。
三次握手的优点:
如果是三次握手的话,当最后一次建立连接过程中的ACK如果丢失的话,服务器会认为没有建立连接成功,而我们的客户端会认为我们的连接已经建立成功了,所以再向服务器发送请求的时候,服务器会做出相应的响应,告诉我们的客户端这是一个无效的连接,通过RST标志,希望重新建立连接,这对服务器来说的话,就不会为无效的连接消耗资源。
洪水攻击
SYN攻击就是客户端不断的向服务器发送SYN包,在短时间内伪造大量的不存在的IP地址,服务器回复确认应答,并等待客户端确认,由于源地址不存在,因此服务器不断的重发到超时,这些伪造的SYN包将长时间的占用未连接队列,导致正常的SYN因为队列满了而丢弃,从而引起网络阻塞甚至系统的瘫痪。
四次挥手
这里写图片描述
四次挥手过程:
客户端向服务器发送FIN希望断开连接请求。
服务器向客户端发送ACK,表示同意释放连接。
服务器向客户端发送一个FIN表示希望断开连接。
客户端向服务器返回一个ACK表示同意释放连接。
服务器状态变化过程:
当客户端主动关闭连接,服务器会受到结束报文段,服务器返回确认报文段,进入CLOSE_WAIT状态。
进入CLOSE_WAIT状态后,说明服务器准备关闭连接;当真正关闭连接时,向客户端发送FIN此时服务器进入LAST_ACK状态。
服务器收到了对端发来的ACK,进入CLOSED状态。
客户端状态变化:
客户端主动向服务器发送结束报文段时,进入FIN_WAIT_1状态
客户端收到服务器对结束报文段的确认时,进入FIN_WAIT_2状态,并等待服务器的结束报文请求。
客户端收到服务器的结束报文段,进入TIME_WAIT状态,并发出最后一个ACK。
客户端必须将时间等待计时器设置成2MSL的时间才会进入CLOSED状态。(MSL叫做最长报文段寿命)。
为什么A在TIME-WAIT之后还要必须等待2MSL的时间呢?理由有两个。
第一点:重发的时候可能丢失ACK报文,因为客户端在收到服务端真正的关闭请求之后就会进入到TIME_WAIT状态,等待2MSL时间,相当于一个报文一来一回的时间,也是就是说,如果客户端的确认应答丢失。算上这个丢失报文的时间,再加上服务端重传FIN的时间(重传后客户端重新启动2MSL计时器),2MSL的时间足够使客户端收到重传的FIN报文段,所以客户端不能立即进入CLOSED状态。
第二点:防止我们以前提到过的已失效的连接请求报文段出现在本连接中。A在发送完了最后一个ACK报文段之后,再经过2MSL,就可以使本连接持续的时间内所产生的所有报文段从网络中消失。这样就可以使下一个新的连接不会出现这种的连接请求报文段。
为什么是TIME_WAIT状态?
1)主动断开连接的一方,会进入TIME_WAIT状态,并没有直接的进入CLOSED状态。
2)进入TIME_WAIT状态的一方,会等待2陪的MSL(最大报文生存时间)的时间。
为什么连接的时候是三次握手,关闭的时候确是四次挥手?
答:因为服务端在收到客户端的SYN连接请求报文之后,可以直接发送SYN+ACK报文,其中的ACK报文是用来进行应答的。SYN报文是用来进行同步的。但是关闭连接时,当服务端收到FIN报文时,很可能不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文我收到了”,只有等到我客户端所有的报文发送完毕,你才能发送报文,一次不能同时进行发送。故需要四次挥手。