连接断开阶段
-
四次挥手机制:TCP连接的断开需要四次挥手,这是因为双方都需要独立地关闭数据传输。第二次和第三次挥手不能合并,因为在回复第二次挥手的时候,可能还有数据没有接收完成,所以需要先回复ACK报文,等待所有的数据接收完成之后再发送FIN报文。这样可以确保数据的完整性。
-
延迟应答:TCP为了提高传输效率,采用了延迟应答的策略。如果没有响应数据要发送,TCP会延迟一段时间,等待是否有响应数据可以一起发送。这样可以减少网络的负载。如果在等待发送ACK期间,对方的第二个数据报文又到达了,这时就会立刻发送ACK。这样可以确保数据的及时性。如果开启了延迟应答的TCP,并且没有响应数据要发送,那么就可能看到ACK和FIN报文合并的情况。这是因为TCP为了提高效率,尽可能地将多个报文合并发送。
-
报文丢失:如果某次挥手的报文丢失了,TCP会进行超时重传,达到最大次数之后就强制断开连接。这是因为TCP为了确保数据的可靠性,采用了超时重传的策略。如果超过一定的时间还没有收到对方的应答,就会认为报文丢失,然后进行重传。
-
主机宕机:如果客户端/服务端建立连接后宕机/断网,会有以下几种情况:
- 未宕机方传输数据:如果服务端向客户端传输数据的过程中发现客户端宕机并重启,客户端的TCP连接的数据结构已经丢失,那么会发送RST报文;如果客户端仍在宕机,服务端会触发超时重传,次数达上限后断开。这是因为TCP为了确保数据的可靠性,采用了超时重传的策略。
- 宕机方传输数据:如果客户端宕机之后重启,希望与同一服务端连接,会发送SYN报文。如果客户端SYN报文中端口号与历史连接相同,服务端会认为这个SYN是乱序的,所以回复历史连接中的正确ACK(Challenge ACK),但是客户端发现这个ACK不是自己希望收到的,就会发送RST,双方断开连接。这是因为TCP为了防止乱序的报文影响到正常的连接,采用了Challenge ACK的策略。
- 长时间无数据传输:为了防止客户端长时间不发送报文占用服务端资源,服务端可以开启TCP保活机制,发送探测报文来探测客户端还是否处于正常状态,否则只有服务端重启才能断开。这是因为TCP为了防止无效的连接占用资源,采用了保活机制。
-
进程崩溃:如果进程崩溃,操作系统会在回收资源的时候代为进行挥手过程,这与主机宕机是不同的,因为TCP的连接信息是由内核维护的。这是因为TCP为了防止进程崩溃导致的资源泄露,采用了进程崩溃后自动断开连接的策略。
-
TIME_WAIT状态:
TIME_WAIT状态是TCP连接断开后的一个必要状态。这个状态的存在有两个主要原因:- 防止旧报文干扰新连接:TIME_WAIT状态可以防止“旧的重复报文”在新的连接中被错误地接收。这是通过让TCP连接在TIME_WAIT状态持续2MSL的时间,使得网络中可能存在的属于“旧连接”的报文都消失,这样新的连接就不会收到旧的报文了。
- 保证正常关闭:TIME_WAIT状态可以确保TCP连接可靠地关闭。这是通过在TIME_WAIT状态期间等待2MSL(报文最大生存时间)来实现的,这样可以保证对方收到了我们的FIN报文,如果对方没有收到,我们可以在这个时间内重发。
-
主动断开连接:
主动断开连接会导致有很多处于TIME_WAIT状态的TCP连接,这会占用系统资源,因此,应该尽量让客户端承受TIME_WAIT。
TCP连接可以在以下几种情况下被主动断开:- 长连接数量达上限:如果长连接的数量达到了系统的上限,系统可能会主动断开一些连接以释放资源。
- 长连接超时:如果客户端长时间无请求,长连接可能会超时,此时服务端可能会主动断开连接。
- 没有使用长连接:如果没有使用长连接(Keep-Alive),短链接一般由服务端主动关闭
-
快速复用:
当TIME_WAIT状态过长会导致占用系统资源过多时,可以选择快速复用,但这相当于放弃了TIME_WAIT的作用,所以最好在保证安全的情况下复用。- tcp_tw_reuse选项:tcp_tw_reuse选项可以快速复用处于TIME_WAIT的连接,但需要配合时间戳一同开启。虽然有了时间戳控制可以避免历史报文,但是历史RST报文只要在接收窗口内就不会丢弃,而且也无法保证被动关闭方正常关闭。
- tcp_tw_recycle选项:tcp_tw_recycle选项也可以快速复用,但是在使用了NAT网络的情况下是不安全的,因为tcp_tw_recycle和时间戳是针对IP地址做PAWS检查的,使用NAT会导致内网下的两个主机会映射到同一个IP,此时两端传输数据包,一端的时间戳会比另一端小,在服务器看来,会认为小的那一端是非法报文,从而丢弃。
- tcp_max_tw_buckets选项:tcp_max_tw_buckets选项可以设定当前主机最多存在的TIME_WAIT状态的TCP连接的数量,当超过这个上限就可以直接关闭。