目录
客户端与服务端四次挥手
关于TIME_WAIT状态
为什么TIME_WAIT状态等待的时间是2MSL?
客户端与服务端四次挥手
基于TCP协议通信的客户端与服务端断开连接就要进行四次挥手,如下图:
四次挥手过程中客户端与服务端状态转化:
客户端
ESTABLISHED->FIN_WAIT1:客户端主动调用close时,向服务器发送结束报文段,同时进入FIN_WAIT1状态。
FIN_WAIT1->FIN_WAIT2:客户端收到服务器对结束报文段的确认,进入FIN_WAIT2状态,开始等待服务器的结束报文段。
FIN_WAIT2->TIME_WAIT:客户端收到服务端发来的结束报文段,并确认应答。
TIME_WAIT->CLOSED:客户端需要等待一个2MSL(Max Segment Life,报文最大存活时间)才会进入CLOSED状态。
服务端
ESTABLISHED->CLOSE_WAIT:客户端主动调用close关闭连接,服务端收到结束报文段并确认应答。
CLOSE_WAIT->LAST_ACK:服务端调用close,向客户端发送结束报文段,等待确认应答。
LAST_ACK->CLOSED:服务器收到最后一个确认应答后连接被关闭。
注意:对于四次挥手,客户端和服务端有先断开连接与后端开断开连接之分。
关于TIME_WAIT状态
做一个测试:
先启动server后启动client,再ctrl+c服务端(ctrl+c就等价于close(fd)先让服务端从状态ESTABLISHED->FIN_WAIT1),然后再ctrl+c客户端,此时在服务端使用指令netstat -ntp会看到server的状态是TIME_WAIT,然后迅速启动server会出现如下情况:
出现绑定套接字失败的错误,TCP协议规定:主动关闭连接的一方,在四次挥手完成后,要处于TIME_ WAIT状态(即连接没有关闭),等待2MSL的时间后才能转化为CLOSED状态连接才能断开,由于server是主动断开连接的一方,四次挥手后进入TIME_WAIT状态仍然不能再次监听同样的server端口因此会出现上图中的报错。
使用setsockopt()设置socket描述符的 选项SO_REUSEADDR为1, 表示允许创建端口号相同但IP地址不同的多个socket描述符
为什么TIME_WAIT状态等待的时间是2MSL?
1、让通信双方历史数据得以消散。MSL是TCP报文的最大生存时间, 因此TIME_WAIT持续存在2MSL就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失(否则服务器立刻重启,可能会收到来自上一个进程的迟到的数据, 但是这种数据很可能是错误的)
2、四次挥手断开连接时,具有较好的容错性。保证最后一个报文可靠到达(假设最后一个ACK丢失, 客户端会再重发一个FIN, 这
时服务端的连接没有断开,客户端仍然可以重发FIN。