一、前言
使用wireshrak抓包的时候,发现有的TCP断开连接,有的是三次挥手、有的是四次挥手,本文将带领带领大家一探究竟。
1. 四次挥手:
四次挥手流程回顾
第一次挥手: 主动关闭的一方(客户端或服务器)发送一个TCP段,其中包含一个FIN标记(Finish),表示它没有数据要发送给对方,但它仍能接收数据。
第二次挥手: 接收到FIN的一方发送一个ACK(Acknowledgement),确认收到FIN。
第三次挥手: 接收到FIN的一方发送一个FIN,表示它也没有数据要发送了,但它仍能接收数据。
第四次挥手: 主动关闭的一方发送一个ACK,确认收到FIN。
2. 三次挥手:
二、原因探索
2.1 现象:
- 三次握手,使用close函数关闭的连接
- 四次握手,使用shutdown函数来关闭的连接
2.2 close
close彻底关闭socket并释放资源
1.调用close函数将会完全关闭socket,不再允许任何读写操作。如果还有数据未发送给对方,系统会尝试在关闭前发送完这些数据(受TCP协议的控制)。在调用close之后,该socket描述符不再有效,不能再被用于读写操作。
2。 系统内核会将socket设置为不可读,任何读操作都会返回异常;在数据发送方向,系统内核尝试将发送缓冲区的数据发送给对端,并最后向对端发送一个FIN报文,接下来如果再对socket进行写操作会返回异常。
2.3 shutdown
shutdown提供了一种更为灵活的方式来关闭socket的一部分功能(接收、发送或两者都关闭)
shutdown函数允许指定关闭操作的类型:
SHUT_RD(0):关闭socket的接收操作。关闭连接的“读”,对该socket进行读操作返回 EOF,并且套接字上接收缓冲区已有的数据将被丢弃,如果再有新的数据流到达,会确认收到数据,返回ACK,但是数据包会被丢弃。
SHUT_WR(1):关闭socket的发送操作。关闭连接的“写”,在这种情况下,连接处于“半关闭”状态。套接字上发送缓冲区已有的数据将被立即发送出去,并发送一个 FIN 报文给对端。应用程序如果对该套接字进行写操作会报错。
SHUT_RDWR(2):同时关闭socket的接收和发送操作。
2.4 进一步原理
「没有数据要发送」并且「开启了 TCP 延迟确认机制」,那么第二和第三次挥手就会合并传输,这样就出现了三次挥手。
TCP延迟确认
- 当有响应数据要发送时,ACK 会随着响应数据一起立刻发送给对方
- 当没有响应数据要发送时,ACK 将会延迟一段时间,以等待是否有响应数据可以一起发送
- 如果在延迟等待发送 ACK 期间,对方的第二个数据报文又到达了,这时就会立刻发送 ACK
挥手流程变化
参考内容:
https://blog.csdn.net/m0_67698950/article/details/126960476
https://blog.csdn.net/qq_61084129/article/details/136407189