TCP协议中三次握手和四次挥手

建立TCP需要三次握手才能建立,而断开连接则需要四次握手。整个过程如下图所示:

首先Client端发送连接请求报文,Server端接受连接请求后回复ACK报文,并为这次连接分配资源。

Client端接收到ACK报文也向Server端发送ACK报文,并分配资源,这样TCP连接就建立了。

断开连接的过程如下:

 

注意:中断连接断可以是Client端,也可以是Server端。

 假设Client端发起中断请求,也就是发送FIN报文。Server端接收到FIN报文后意思说:“我Client没有数据要发给你了”,但是如果你还有数据没有发送完成给我,不用着急关闭socket,可以继续发送数据。所以Server先发送ACK,“告诉Client我收到了你的关闭请求,但是我还没有准备好,请继续等待我的消息”。这个时候Client端就进入了FIN_WAIT状态,继续等待Server端的FIN报文。当Sever端的数据发送完成,则向Client端发送FIN报文,“告诉Client端,我这边数据都发送完了,准备好关闭连接了”。Client端接收到FIN报文后,“就知道可以关闭连接了,但是他还是不能相信网络,怕Sever端不知道要关闭了,所以发送ACK后进入TIME_WAIT状态,如果Server没有接收到ACK则可以重传”,Server接收到ACK之后,“就知道可以断开连接了”。Client等待2MSL后依然没有收到回复,证明Server端已经正常关闭,那么Client端也可以关闭连接了。

 

【注意】 在TIME_WAIT状态中,如果TCP client端最后一次发送的ACK丢失了,它将重新发送。TIME_WAIT状态中所需要的时间是依赖于实现方法的。典型的值为30秒、1分钟和2分钟。等待之后连接正式关闭,并且所有的资源(包括端口号)都被释放。

 

【问题1】为什么连接的时候是三次握手,关闭的时候却是四次握手?
答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
 

【问题2】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。
 

孤儿连接 
连续停留在FIN_WAIT2状态可能发生,客户端执行半关闭状态后,未等服务器关闭连接就直接退出了,此时客户端连接由内核接管。Linux为防止孤儿连接长时间存在内核中,定义了两个变量指定孤儿连接数目和生存时间。

 

半连接队列全连接队列

从服务端来说,三次握手中,第一步server接受到client的syn后,把相关信息放到半连接队列中,同时回复syn+ack给client. 第三步当收到客户端的ack, 将连接加入到全连接队列。

一般,全连接队列比较小,会先满,此时半连接队列还没满。如果这时收到syn报文,则会进入半连接队列,没有问题。但是如果收到了三次握手中的第3步(ACK),则会根据tcp_abort_on_overflow字段来决定是直接丢弃,还是直接reset.此时,客户端发送了ACK, 那么客户端认为三次握手完成,它认为服务端已经准备好了接收数据的准备。但此时服务端可能因为全连接队列满了而无法将连接放入,会重新发送第2步的syn+ack, 如果这时有数据到来,服务器TCP模块会将数据存入队列中。一段时间后,client端没收到回复,超时,连接异常,client会主动关闭连接。

 参考文献:

https://www.cnblogs.com/qcrao-2018/p/10182185.html#%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B%E5%9B%9B%E6%AC%A1%E6%8C%A5%E6%89%8B

https://blog.csdn.net/whuslei/article/details/6667471/

你可能感兴趣的:(操作系统)