TCP连接释放−四次挥手

- 第一次挥手:客户端发送连接释放报文,并且停止发送数据;
- 第二次挥手:服务器收到连接释放报文,发回确认报文,客户端向服务器的方向就释放了,此时处于半关闭状态。一个FIN占用一个序号;
- 第三次挥手:服务器将最后的数据发送完毕后,向客户端发送连接释放报文;
- 第四次挥手:客户端收到服务器的连接释放报文后,必须发出确认,然后服务器只要收到了客户端发出的确认,关闭连接,完成四次挥手。
为什么是四次挥手?
关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发给你了,但未必你所有的数据全都发送给对方了,所以有可能你还需要发送一些数据给对方,然后再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以ACK报文和FIN多数情况下是分开发送的。
四次挥手后有个TIME_WAIT,为什么需要TIME_WAIT?
-主动发起连接关闭的一方再发送最后一个ACK后进入TIME_WAIT状态等待2MSL时间后回到初始状态(closed)
- 等待2MSL是为了确保最后一次发送的ACK被对方接收。

服务端停止服务,主动断开tcp连接是否需要进入TIME-WAIT状态?
当服务端主动断开TCP连接时,它会发送一个FIN(结束)消息给客户端,然后进入TIME-WAIT状态。
在TIME-WAIT状态中,服务端等待一段时间以确保客户端已经收到了它发送的FIN消息的确认,并且确保在网络中所有的数据包都已经被丢弃。
这个等待时间通常为2倍的最大报文段生命周期(2MSL,Maximum Segment Lifetime),通常为几分钟到几分钟。在这个等待时间内,服务端的端口将不可用,以防止旧的重复数据包被新的连接误解。
进入TIME-WAIT状态的目的是为了确保网络中的所有数据包都已经被清除,从而避免新的连接错误地处理之前连接的残留数据。此外,TIME-WAIT状态还允许以前的连接的最后一些数据包在网络中自然过期,而不会影响到新的连接。
为什么测试停掉httpd服务,没有发现它跟客户端之前的tcp连接进入TIME-WAIT 状态?
# systemctl stop httpd
在一般情况下,无论是客户端还是服务端主动断开TCP连接,都会经历TIME-WAIT状态。
TIME-WAIT状态的存在是为了确保连接的可靠关闭,防止之前的数据包在网络中滞留导致混乱。
在TIME-WAIT状态下,系统等待一段时间(通常是2MSL)确保对端收到了连接关闭的通知,然后才会完全关闭连接并释放资源。
如果服务端停止服务后不进入TIME-WAIT状态,可能会导致一些问题,比如可能会造成之前的连接状态混乱,影响网络稳定性和安全性。因此,通常情况下,主动断开TCP连接都会经历TIME-WAIT状态。
当HTTP服务器(如httpd)停止服务时,它会关闭所有当前打开的连接。
在这种情况下,HTTP服务器是通过发送FIN来关闭TCP连接的,然后它的端口会立即变为可用状态,而不会进入TIME-WAIT状态。这是因为在服务器主动关闭连接时,它已经完成了所有必要的步骤,确保数据的正常传输和连接的关闭。因此,TIME-WAIT状态通常不会出现在服务器主动关闭连接的情况下。
TIME-WAIT状态通常是在客户端主动关闭连接时出现的,以确保服务器端正确处理连接的关闭,同时避免旧连接的数据包与新连接混淆。
为什么客户端主动断开tcp连接需要进入TIME-WAIT状态?
客户端在主动断开TCP连接后需要进入TIME-WAIT状态是为了确保连接的可靠性和完整性。TIME-WAIT状态是TCP协议设计的一种机制,用于处理网络中可能存在的延迟、重传、乱序等问题,以确保数据能够正确传输完毕。
在客户端主动断开TCP连接的情况下,客户端发送一个FIN包给服务端,表示要关闭连接。服务端接收到FIN包后会发送一个ACK包给客户端,确认收到了关闭请求。此时客户端进入TIME-WAIT状态,等待一段时间后才会关闭连接。
客户端进入TIME-WAIT状态的主要作用有以下几点:
- 确保服务端收到了客户端的关闭请求,避免数据丢失或重传的情况。
- 等待一段时间,确保网络中所有的数据包都能够传输完毕,避免数据乱序或延迟带来的问题。
- 防止之前连接的残留数据影响新连接的建立。
虽然TIME-WAIT状态会占用一定的资源和连接建立时间,但这是为了保证数据传输的完整性和可靠性,从而提高网络通信的质量。
80 端口已被处于TIME-WAIT状态的tcp连接占用了,为什么服务还可以 LISTEN 在80端口上?
# ss -tan | grep 80
LISTEN 0 511 [::]:80 [::]:*
TIME-WAIT 0 0 [::ffff:10.23.65.44]:80 [::ffff:38.207.136.80]:56260
TIME-WAIT 0 0 [::ffff:10.23.65.44]:80 [::ffff:38.207.136.80]:55831
TIME-WAIT 0 0 [::ffff:10.23.65.44]:80 [::ffff:38.207.137.254]:62792
TIME-WAIT 0 0 [::ffff:10.23.65.44]:80 [::ffff:38.207.137.254]:62652
TIME-WAIT 0 0 [::ffff:10.23.65.44]:80 [::ffff:38.207.137.254]:27801
# systemctl restart httpd
在你提供的输出中,可以看到一些TCP连接处于TIME-WAIT状态,而端口80仍然处于LISTEN状态。这种情况是可能的,因为TIME-WAIT状态是针对已经关闭的连接的,而LISTEN状态是用于等待新连接的状态。
TIME-WAIT状态的连接不会阻止端口处于LISTEN状态。
LISTEN状态表示服务器正在监听新的连接请求,并且可以接受新的连接,即使存在一些先前的连接处于TIME-WAIT状态,服务器仍然可以继续监听并接受新的连接请求。
因此,端口80仍然处于LISTEN状态,可以接受新的连接,即使存在一些旧的连接处于TIME-WAIT状态。
MSL和TTL的关系
MSL 是 Maximum Segment Lifetime,报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
因为 TCP 报文基于是 IP 协议的,而 IP 头中有一个 TTL 字段,是 IP 数据报可以经过的最大路由数,每经过一个处理他的路由器此值就减 1,当此值为 0 则数据报将被丢弃,同时发送 ICMP 报文通知源主机。
MSL 与 TTL 的区别: MSL 的单位是时间,而 TTL 是经过路由跳数。所以 MSL 应该要大于等于 TTL 消耗为 0 的时间,以确保报文已被自然消亡。
TTL 的值一般是 64,Linux 将 MSL 设置为 30 秒,意味着 Linux 认为数据报文经过 64 个路由器的时间不会超过 30 秒,如果超过了,就认为报文已经消失在网络中了。
参考
聊聊 IP packet 的 TTL 与 tcp segment 的 MSL
https://mp.weixin.qq.com/s/d2kDlx-_fZE_vTLL60-2Vw
你真的了解 socket 编程吗?
https://mp.weixin.qq.com/s/XheR4nwElJSWX4VvCwSBDA
网友评论