TCP的连接是全双工的,所以连接的拆除需要单独将两个通道分别拆除,而四次挥手所做的事情就是拆除两条通道和释放资源。
TCP 提供了连接的一端结束他的发送后,还能接收来自另一端数据的能力,也就是所谓的半关闭。
TCP/IP详解卷I
这里以Client作为主动发起端,Server作为被动关闭端。
第一步,Client主动发起一个Req给Server,里面包含FIN标识位=1,CLient的Seq序列号N,表示的是当前Client在该连接上的当前序列号。
第二步,Server端在收到这个含有FIN的Req消息之后,校验无误之后会立马回复ACK消息给CLient端,消息内部包含ACK标志位为1,同时Seq号码是FIN的请求消息的Seq号+1。此时的Sever同时会主动发个结束标识给Server上面的应用层程序,应用层程序可以决定是立马结束,还是等到服务器上面的该连接中的数据处理完了之后,在发送FIN消息给Client来关掉另外的一半连接。
第三步,Server端在处理完该连接上面的Pending住的数据之后,应用程序会close这个连接。Client会主动发起FIN的Req消息给Client端。消息内部带有,FIN=1的结束符标识位,以及Server端的Seq序列号。
第四步,Client端在收到对应的FIN消息之后,会主动通知应用层程序,告知这个连接现在需要关闭了。然后,Client会回复ACK消息给Server,以便断开另外一个方向的通道,这个消息包含ACK=1的标识位和FIN的REQ带过来的Seq+1。
因为TCP是一个全双工协议,必须单独拆除每一条信道。4次挥手的目的是终止数据传输,并回收资源,此时两个端点两个方向的序列号已经没有了任何关系,必须等待两方向都没有数据传输时才能拆除虚链路,不像初始化时那么简单,发现SYN标志就初始化一个序列号并确认SYN的序列号。因此必须单独分别在一个方向上终止该方向的数据传输。
如果是三次挥手,会怎么样?三次的话,被动关闭端在收到FIN消息之后,需要同时回复ACK和Server端的FIN消息。如果Server端在该连接上面并没有Pending的消息要处理,那么是可以的,如果Server端还需要等待一段时间才可以关闭另外一个方向的连接,那么这样的三次挥手就不能满足条件。
Client端:
ESTABLISHED---发送FIN给Server-->FIN_WAIT_1---接收到Server端的FIN对应的ACK-->FIN_WAIT_2---收到Server端发送过来的FIN消息-->FIIN_WAIT--2MSL之后会进入-->CLOSED
Server端:
ESTABLISHED---接收到Client端的FIN->CLOSED_WAIT--Server端的应用程序关闭发送FIN--> LAST_ACK---收到Client对于FIN的ACK响应-->FIIN_WAIT---->CLOSED
Tcp/ip详解 卷I
其中四次挥手与Scoket函数的对应关系如下所示:
图片来自网络,如有侵权请告知,会及时删除
四次挥手里面,最经典的场景,是Client处于TIME_WAIT之后的2MSL的时间处理。(备注:MSL是TCP报文里面最大生存时间,它是任何报文段被丢弃前在网络内的最长时间。)
设置2MSL的目的是为了处理,Server端在重传最后一个FIN的时候,Client能够发送最后一个ACK的时间。
这个时间段内,不管是Client端还是Server端,最好都不要重用这个TCP的端口,否则的话,可能会导致根据这个端口新建立的连接被错误的关掉,详细情况如下所示:
step1:Server发送给Client的最后一个FIN,Client收到了,也发了ACK给Server,但是Server并没有收到这个ACK。step2:于是CLient复用了这个Port号,于是新建了一条连接,这里假设叫newConnection。step3:Server在此过程中已经发送了重传的FIN给Client,Client上面刚建立完成的newConnection就会再次被关掉。
https://blog.csdn.net/qq_34501940/article/details/51119726
https://blog.csdn.net/varyall/article/details/80348850
TCP/IP详解 卷1