真实面经题目 · 原创解析
TCP如何识别断开?
TCP 识别断开依赖报文、应用读写行为和超时机制共同完成。正常关闭通常通过 FIN 体现,应用读到 0;异常关闭常见为 RST,读写报错;静默断链不会立刻被发现,需要 keepalive、应用层心跳和业务超时兜底。
真实面经题目 · 原创解析
TCP 识别断开依赖报文、应用读写行为和超时机制共同完成。正常关闭通常通过 FIN 体现,应用读到 0;异常关闭常见为 RST,读写报错;静默断链不会立刻被发现,需要 keepalive、应用层心跳和业务超时兜底。
可以分三类回答。第一类是正常关闭:对端调用 close 或 shutdown 后发送 FIN,本端内核收到 FIN 后进入对应关闭状态,应用层继续读 socket,如果缓冲区已经读完,会读到 0,表示对端发送方向关闭。第二类是异常关闭:对端进程崩溃、端口无对应连接、强制关闭或向已不存在的连接发数据,都可能产生 RST,本端在 read 或 write 时得到 ECONNRESET;继续向已关闭读端写入还可能出现 EPIPE 或 SIGPIPE。第三类是静默失效:拔网线、机器断电、移动网络切换、NAT 映射消失、防火墙丢弃空闲连接时,双方可能收不到 FIN 或 RST,连接在本地仍显示存在,只有后续发数据、重传失败、TCP keepalive 失败、应用层心跳超时或业务超时后才会发现。工程上不能只等系统通知,长连接一般会组合 read 返回 0、读写错误码、连接超时、读写超时、idle 超时、TCP keepalive 和应用层 ping/pong。排查时要对齐客户端、服务端和中间设备时间,看日志错误码、TCP 状态、抓包中的 FIN、RST、重传和 keepalive 探测。
正常关闭通常表现为 FIN。对端发送 FIN 代表它不再发送数据,但 TCP 支持半关闭,本端仍可能继续发送。应用层在接收缓冲区数据读完后 read 返回 0,这个 0 是 EOF,不是错误,也不是超时。
RST 表示连接被重置,常见于对端异常退出、端口没有对应连接、应用强制关闭或协议状态不一致。本端读写时可能得到 ECONNRESET,说明原会话已经不可继续使用,需要关闭连接并按业务策略重连。
write 成功不等于对端应用已经收到,只代表数据进入了本机发送缓冲区或被内核接收处理。若对端已经重置,后续 write 可能返回 ECONNRESET;若继续向关闭的读端写,类 Unix 系统可能返回 EPIPE 并触发 SIGPIPE。
静默断链最难处理。断电、拔网线、移动网络切换、NAT 映射过期时,不一定有 FIN 或 RST 到达另一端,因此本地连接可能仍处于 ESTABLISHED。没有数据交互时,内核可能很久都不知道连接已经不可用。
TCP keepalive 是内核级空闲探测,适合清理半开连接,但默认周期通常很长。应用层心跳更可控,可以用较短 ping/pong 周期判断对端应用是否仍可处理请求。业务还要设置连接、读写、请求和空闲超时。
排查要先判断是 FIN、RST 还是超时。FIN 偏正常生命周期,RST 偏异常重置,超时偏链路或中间设备静默丢弃。再结合客户端日志、服务端日志、socket 错误码、TCP 状态和抓包,定位真正断开点。
read 返回 0 通常是对端正常关闭发送方向,属于 EOF;返回 -1 表示发生错误,需要看 errno,常见有 ECONNRESET、ETIMEDOUT、EAGAIN 等。
拔网线不会自动产生 FIN 或 RST,服务端没有收到任何控制报文,本地状态仍可能是 ESTABLISHED。只有发包重传失败、keepalive 失败或心跳超时后才会发现。
TCP keepalive 由内核维护,判断连接路径大致是否可达;应用心跳由业务协议维护,能判断对端应用是否还活着、是否还能处理请求,周期也更容易按业务调整。
通常结合空闲超时、读写超时、TCP keepalive、应用层心跳、连接池生命周期管理和错误码处理。只等待客户端主动 close,在公网和移动网络场景下不可靠。