TCP四次挥手
四次挥手
以上过程流程图如下:
为什么断开连接需要四次握手?因为TCP链接是全双工的,即数据在两个方向上能同时传递,因此每个方向必须单独的进行关闭。这原则就是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向连接。
分析
TCP报文头中flags中的FIN被置为1,sequence number=418, acknowledgment number=203。返回一个确认报文,ack=seq+1=419,seq = ack=203。至此,source port23到dst port=54203方向的数据传输终止了。
然后它(54203)向23方向发出一个FIN报文,要求终结他到23方向的数据传输。
TCP的半关闭
TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。这就是所谓的半关闭。即“我已经完成了数据传送,因此发送一个文件结束(FIN)给另一端,但我还想接收另一端发来的数据。
为什么要有半关闭?
有了半关闭,客户端能知道对段数据传完了(因为对方数据传输结束后会发送一个FIN),然后客户端才能对接收到的数据进行处理。假如没有半关闭技术,我们需要其他更复杂的技术来通知对方我们数据已经传输结束了。
FIN_WAIT_1状态
客户端主动发送FIN报文,主动请求关闭。于是进入FIN_WAIT_1状态。
如果服务器出现shutdown再重启,使用netstat -nat查看,就会看到很多FIN-WAIT-1的状态。就是因为服务器当前有很多客户端连接,直接关闭服务器后,无法接收到客户端的ACK。
FIN_WAIT_2状态(著名的半关闭状态)
在FIN_WAIT_2状态我们已经发出了FIN,并且另一端也已对它进行确认。除非我们实行半关闭,否则将等待另一端的应用层意识到它已经收到一个文件结束符,并向我们发一个FIN来关闭另一方向的连接。只有当另一端的进程完成这个关闭,我们这段才会从FIN_WAIT_2状态进入TIME_WAIT状态。
处于FIN_WAIT状态时,应用程序还有接收数据的能力,只是不会再发送数据了(除了为了回应被动关闭端的FIN报文而发送ACK)。
这就意味着我们这端可能永远保持FIN_WAIT_2状态。另一端也将处于CLOSE_WAIT状态,并一直保持这个状态直到应用层决定进行关闭。
CLOSE_WAIT状态
被动关闭端接收到FIN报文后,返回一个确认报文ACK,以回应FIN报文。于是进入CLOSE_WAIT状态。
LAST_ACK状态
被动关闭端进入CLOSE_WAIT一段时间后,应用层会调用CLOSE函数关闭连接。此时会向另一端发出一个FIN报文,并等待FIN的ACK报文。发出FIN报文后,收到ACK之前这段时间被动关闭端处于LAST_ACK状态。
TIME_WAIT状态(2MSL等待状态)
2MSL也称为TINME_WAIT状态。每个具体TCP实现必须选择一个报文段最大生存时间MSL(maximum segment Lifetime)。它是任何报文被丢弃前在网络内的最长时间。对一个具体实现给定的MSL值,处理原则是:当TCP执行一个主动关闭,并发回最后一个ACK,该连接必须在TIME_WAIT状态停留的时间为2倍的MSL。这样可以让TCP最后的ACK以防止这个ACK丢失(另一个短超时并重发最后的FIN)。
这种2MSL等待的另一个结果是这个TCP连接在2MSL等待期间,等一连接这个的socket(ip+port)不能再被使用。这个连接只能只能在2MSL结束后才能再被使用。
CLOSED状态
被动关闭端在接受到ACK包后,就进入了closed的状态。连接结束。/* The socket is not being used. 没有任何连接状态。
复位报文段
TCP首部中的RST标志位用于“复位”。