大厂校招题:服务端挂了,客户端的 TCP 连接会发生什么?

张开发
2026/4/17 9:15:19 15 分钟阅读

分享文章

大厂校招题:服务端挂了,客户端的 TCP 连接会发生什么?
收到一位读者的私信说字节面试有这么一个问题服务端挂了客户端的 TCP 连接会发生什么如果「服务端挂掉」指的是「服务端进程崩溃」那么这个读者猜的想法是对的服务端的进程在发生崩溃的时候内核会发送 FIN 报文与客户端进行四次挥手。但是如果「服务端挂掉」指的是「服务端主机宕机」那么是不会发生四次挥手的具体后续会发生什么还要看客户端会不会发送数据如果客户端会发送数据由于服务端已经不存在客户端的数据报文会超时重传当重传次数达到一定阈值后会断开 TCP 连接如果客户端一直不会发送数据再看客户端有没有开启 TCP keepalive 机制如果有开启客户端在一段时间后检测到服务端的 TCP 连接已经不存在则会断开自身的 TCP 连接如果没有开启客户端的 TCP 连接会一直存在并不会断开。上面属于精简回答了下面我们详细聊聊。服务端进程崩溃客户端会发生什么TCP 的连接信息是由内核维护的所以当服务端的进程崩溃后内核需要回收该进程的所有 TCP 连接资源于是内核会发送第一次挥手 FIN 报文后续的挥手过程也都是在内核完成并不需要进程的参与所以即使服务端的进程退出了还是能与客户端完成 TCP四次挥手的过程。我自己也做了实验使用 kill -9 命令来模拟进程崩溃的情况发现在 kill 掉进程后服务端会发送 FIN 报文与客户端进行四次挥手。服务端主机宕机后客户端会发生什么当服务端的主机突然断电了这种情况就是属于服务端主机宕机了。当服务端的主机发生了宕机是没办法和客户端进行四次挥手的所以在服务端主机发生宕机的那一时刻客户端是没办法立刻感知到服务端主机宕机了只能在后续的数据交互中来感知服务端的连接已经不存在了。因此我们要分两种情况来讨论服务端主机宕机后客户端会发送数据服务端主机宕机后客户端一直不会发送数据服务端主机宕机后如果客户端会发送数据在服务端主机宕机后客户端发送了数据报文由于得不到响应在等待一定时长后客户端就会触发超时重传机制重传未得到响应的数据报文。当重传次数达到达到一定阈值后内核就会判定出该 TCP 连接有问题然后通过 Socket 接口告诉应用程序该 TCP 连接出问题了于是客户端的 TCP 连接就会断开。那 TCP 的数据报文具体重传几次呢在 Linux 系统中提供了一个叫 tcp_retries2 配置项默认值是 15如下图这个内核参数是控制在 TCP 连接建立的情况下超时重传的最大次数。不过 tcp_retries2 设置了 15 次并不代表 TCP 超时重传了 15 次才会通知应用程序终止该 TCP 连接内核会根据 tcp_retries2 设置的值计算出一个 timeout如果 tcp_retries2 15那么计算得到的 timeout 924600 ms如果重传间隔超过这个 timeout则认为超过了阈值就会停止重传然后就会断开 TCP 连接。在发生超时重传的过程中每一轮的超时时间RTO都是倍数增长的比如如果第一轮 RTO 是 200 毫秒那么第二轮 RTO 是 400 毫秒第三轮 RTO 是 800 毫秒以此类推。而 RTO 是基于 RTT一个包的往返时间 来计算的如果 RTT 较大那么计算出来的 RTO 就越大那么经过几轮重传后很快就达到了上面的 timeout 值了。举个例子如果 tcp_retries2 15那么计算得到的 timeout 924600 ms如果重传总间隔时长达到了 timeout 就会停止重传然后就会断开 TCP 连接如果 RTT 比较小那么 RTO 初始值就约等于下限 200ms也就是第一轮的超时时间是 200 毫秒由于 timeout 总时长是 924600 ms表现出来的现象刚好就是重传了 15 次超过了 timeout 值从而断开 TCP 连接如果 RTT 比较大假设 RTO 初始值计算得到的是 1000 ms也就是第一轮的超时时间是 1 秒那么根本不需要重传 15 次重传总间隔就会超过 924600 ms。最小 RTO 和最大 RTO 是在 Linux 内核中定义好了#define TCP_RTO_MAX ((unsigned)(120*HZ)) #define TCP_RTO_MIN ((unsigned)(HZ/5))Linux 2.6 使用 1000 毫秒的 HZ因此TCP_RTO_MIN约为 200 毫秒TCP_RTO_MAX约为 120 秒。如果tcp_retries设置为15且 RTT 比较小那么 RTO 初始值就约等于下限 200ms这意味着它需要 924.6 秒才能将断开的 TCP 连接通知给上层即应用程序每一轮的 RTO 增长关系如下表格服务端主机宕机后如果客户端一直不发数据在服务端主机发送宕机后如果客户端一直不发送数据那么还得看是否开启了 TCP keepalive 机制 TCP 保活机制。如果没有开启TCP keepalive 机制在服务端主机发送宕机后如果客户端一直不发送数据那么客户端的 TCP 连接将一直保持存在所以我们可以得知一个点在没有使用 TCP 保活机制且双方不传输数据的情况下一方的 TCP 连接处在 ESTABLISHED 状态时并不代表另一方的 TCP 连接还一定是正常的。而如果开启了 TCP keepalive 机制在服务端主机发送宕机后即使客户端一直不发送数据在持续一段时间后TCP 就会发送探测报文探测服务端是否存活如果对端是正常工作的。当 TCP 保活的探测报文发送给对端, 对端会正常响应这样TCP 保活时间会被重置等待下一个 TCP 保活时间的到来。如果对端主机崩溃或对端由于其他原因导致报文不可达。当 TCP 保活的探测报文发送给对端后石沉大海没有响应连续几次达到保活探测次数后TCP 会报告该 TCP 连接已经死亡。所以TCP keepalive 机制可以在双方没有数据交互的情况通过探测报文来确定对方的 TCP 连接是否存活。TCP keepalive 机制具体是怎么样的TCP keepalive 机制机制的原理是这样的定义一个时间段在这个时间段内如果没有任何连接相关的活动TCP 保活机制会开始作用每隔一个时间间隔发送一个探测报文该探测报文包含的数据非常少如果连续几个探测报文都没有得到响应则认为当前的 TCP 连接已经死亡系统内核将错误信息通知给上层应用程序。在 Linux 内核可以有对应的参数可以设置保活时间、保活探测的次数、保活探测的时间间隔以下都为默认值net.ipv4.tcp_keepalive_time7200 net.ipv4.tcp_keepalive_intvl75 net.ipv4.tcp_keepalive_probes9每个参数的意思具体如下tcp_keepalive_time7200表示保活时间是 7200 秒2小时也就 2 小时内如果没有任何连接相关的活动则会启动保活机制tcp_keepalive_intvl75表示每次检测间隔 75 秒tcp_keepalive_probes9表示检测 9 次无响应认为对方是不可达的从而中断本次的连接。也就是说在 Linux 系统中最少需要经过 2 小时 11 分 15 秒才可以发现一个「死亡」连接。注意应用程序如果想使用 TCP 保活机制需要通过 socket 接口设置 SO_KEEPALIVE 选项才能够生效如果没有设置那么就无法使用 TCP 保活机制。TCP keepalive 机制探测的时间也太长了吧对的是有点长。TCP keepalive 是TCP 层内核态实现的它是给所有基于 TCP 传输协议的程序一个兜底的方案。实际上我们应用层可以自己实现一套探测机制可以在较短的时间内探测到对方是否存活。比如web 服务软件一般都会提供 keepalive_timeout 参数用来指定 HTTP 长连接的超时时间。如果设置了 HTTP 长连接的超时时间是 60 秒web 服务软件就会启动一个定时器如果客户端在完后一个 HTTP 请求后在 60 秒内都没有再发起新的请求定时器的时间一到就会触发回调函数来释放该连接。总结如果「服务端挂掉」指的是「服务端进程崩溃」服务端的进程在发生崩溃的时候内核会发送 FIN 报文与客户端进行四次挥手。但是如果「服务端挂掉」指的是「服务端主机宕机」那么是不会发生四次挥手的具体后续会发生什么还要看客户端会不会发送数据如果客户端会发送数据由于服务端已经不存在客户端的数据报文会超时重传当重传总间隔时长达到一定阈值内核会根据 tcp_retries2 设置的值计算出一个阈值后会断开 TCP 连接如果客户端一直不会发送数据再看客户端有没有开启 TCP keepalive 机制如果有开启客户端在一段时间没有进行数据交互时会触发 TCP keepalive 机制探测对方是否存在如果探测到对方已经消亡则会断开自身的 TCP 连接如果没有开启客户端的 TCP 连接会一直存在并且一直保持在 ESTABLISHED 状态。

更多文章