TCP — 连接与可靠性是怎么造出来的
一句话总结
TCP 通过序列号、确认、重传和两种窗口,营造“既不丢失也不乱序的字节流”这一抽象。
为什么需要它
IP 只尽力而为,不作任何承诺。数据包可能丢失、乱序或重复,而多数应用都假设“按发送顺序接收”。TCP 用来弥合这一差距。
工作原理
建立连接。 客户端发送 SYN,服务器回复 SYN-ACK,客户端再发送 ACK。之所以需要三次交换,是因为双方都要向对方公布并确认自己的初始序列号。
关闭连接。 两个方向分别关闭,因此 FIN 和 ACK 各出现两次,共四次交换。主动关闭方会保持 TIME-WAIT 状态 2MSL(最大报文段寿命的两倍),防止迟到报文污染复用同一端口对的新连接,并在最后一个 ACK 丢失时能够重发。高负载服务器存在数万个 TIME-WAIT 套接字很正常,为消除它们而随意修改内核参数反而会引发问题。
可靠性。 接收方用 ACK 告知连续收到的位置。发送方在一定时间(RTO)内未获确认就重传;同一个 ACK 重复三次时,不等超时便立即重传(快速重传)。
两个窗口。 流量控制通过接收方公布的接收窗口(rwnd)表示“我只能接收这么多”;拥塞控制通过发送方维护的拥塞窗口(cwnd)估计“网络只能承受这么多”。两者目的不同。 实际发送量受较小者限制。拥塞窗口在慢启动阶段指数增长,超过阈值后线性增长,检测到丢包后大幅缩小(AIMD)。
实际工作中的表现
两种连接失败消息的区别决定了诊断方向。
Connection refused 表示对方返回了 RST。 这证明数据包已到达目的地并返回,路由、安全组和网络策略均已通过。问题在目标主机内部:进程已退出、监听了其他端口、没有绑定 0.0.0.0 而是只绑定 127.0.0.1,或负载均衡器后没有健康后端。“出现 refused 所以是防火墙”通常是错的。 实际防火墙多采用静默丢弃(DROP),无响应会表现为 timeout。
Connection timed out 表示 SYN 重传耗尽仍无响应。 Linux 默认重传 tcp_syn_retries 次,间隔逐次翻倍。1+2+4+8+16+32+64 合计 127 秒。若应用配置超时为 30 秒,却实际 127 秒才失败,说明该配置并未生效。
即使存在监听器也可能 timeout。accept 队列已满时,内核会静默丢弃新 SYN。用 ss -ltn 查看监听套接字时,Recv-Q 是当前队列长度,Send-Q 是上限。若 Recv-Q 已逼近或超过 Send-Q,原因是应用吞吐量而不是网络。
后续测验将确认什么
确认你能解释 refused 与 timeout 分别对应怎样的数据包交换,以及流量控制与拥塞控制有何不同。