1. 四次挥手步骤
序列号与确认号规则不再叙述。ACK在建立连接之后都是1
- 当主动方关闭连接时,会发送FIN报文,此时发送方的TCP连接从established变为fin_wait_1
- 当被动方收到FIN报文后,内核会自动回复ack报文,被动方连接状态从established变为close_wait。表示被动方在等待进程调用close函数关闭连接
- 当主动放收到了这个ack后,主动方连接有fin_wait_1变为fin_wait_2,表示主动方的发送通道就关闭了。
- 当被动方进入close_wait时,被动方还会继续处理数据,等待进程read函数返回0后,应用程序就会调用close函数,进而触发内核发送FIN报文。此时被动方的连接状态变为last_ack
- 当主动方收到这个FIN报文后,内核会自动回复ack报文给被动方,同时主动方的连接状态由fin_wait_2变为time_wait,在linux系统下大约等待1分钟(2MSL)后,time_wait状态的连接才会彻底关闭。注意:主动关闭连接的,才有time_wait状态。
2. CLOSE_WAIT状态得意义
- 客户端发送了FIN连接释放报文请求后,服务端收到了这个报文,就进入CLOSE-WAIT状态,
- 这个状态时为了让服务端发送为传送完毕的数据,传送完毕后,服务器会发送FIN连接释放请求报文。
3. TIME_WAIT状态的意义
- 客户端接收到服务端的FIN报文后会进入此状态,此时并不是直接进入CLOSED状态,还需要等待一个时间计时器设置的时间2MSL(报文最大生存时间,linux中默认MSL=30s。)。这么做有两个理由:
- 确保最后一个确认报文能够到达,如果B没有收到A发送来的确认报文,那么B就会重新发送连接释放请求报文,A等待一段时间就是为了处理这种情况的发生。(即保证最后一次ack能让被动关闭放接收,从而帮助其正常关闭)
- 等待一段时间也是为了让本连接持续时间内所产生的所有报文都从网络上消逝,使得下一个新连接不会收到旧的连接的请求报文。(即防止有相同四元组的旧数据包被接收到)(补充:但是我觉得这个意义不大,因为每次连接都会随机初始化一个初始序列号,而且这个初始序列号也是递增的。所以旧的连接的报文的序列号被收到了也应该能够去判断这是上一个连接的,可以丢弃。)
4. 等待2MSL会产生得问题
- 如果服务端主动关闭大量得连接,那么会出现大量得资源占用,需要等待2MSL才会释放资源
- 如何解决
- 调小TIME_WAIT得时间
- 建议服务端不要主动关闭,把主动关闭放到客户端。