TCP, 三次握手, 四次挥手, 滑动窗口, 快速重传, 拥塞控制, 半连接队列, RST, SYN, ACK

目录


TCP 是什么:面向连接 + 可靠 + 字节流

  • 面向连接:通信前需要建立连接(三次握手)。
  • 可靠交付:通过序列号、确认号、校验和、重传、窗口等保证不丢、不重、按序到达(应用层"看起来"按序)。
  • 字节流:没有消息边界,数据是连续字节流,分段与拼包在传输层完成。

简图(字节流与按序):

复制代码
[App 写入字节] => [TCP 分段 seq=100..] => [网络] => [TCP 重组、去重、排序] => [App 读到连续字节]

三次握手:为什么不是两次

三次握手的目标:

  • 交换初始序列号(ISN)并建立双向通信能力。
  • 让客户端和服务端都"确认"对方的收发能力都正常。

流程(简化):

复制代码
CLOSE -> SYN-SENT --SYN(x)--> LISTEN
SYN-RCVD <--SYN(y),ACK(x+1)-- LISTEN
ESTABLISHED --ACK(y+1)--> ESTABLISHED

为什么不能两次?

  • 若两次握手,服务端无法判断当前请求是否"历史连接"重放;第三次 ACK 让客户端基于上下文确认"我确实与这个服务端建立了当前连接",避免"僵尸连接"占用资源。

我常用的比喻:

  • 第一次:我能发(SYN)。
  • 第二次:我能收能发(SYN+ACK)。
  • 第三次:我也能收(ACK),双方都齐活。

注:半连接队列记录"收到 SYN 尚未完成握手"的请求;若第三次 ACK 不到,条目会因超时被清理。


四次挥手与 TIME_WAIT:谁等谁

为什么"挥手"通常是四次?

  • 关闭是"单向"的:一方 FIN 只表示"我不再发了",对方读到 FIN 但仍可继续发送,故需要两对报文确保双方各自完成"发送通道"的关闭。

典型序列:

复制代码
(主动关闭)  FIN -> ACK    (被动方进 CLOSE_WAIT)
             ...对方数据发送完...
             FIN -> ACK    (主动方进 TIME_WAIT)

TIME_WAIT 的意义:

  • 等 2MSL,确保:
    • 最后的 ACK 若丢失,对方重发 FIN,我还能重发 ACK;
    • 旧连接的迟到报文不会影响未来新的同四元组连接。

调优提示:

  • 服务端侧可让"短连接风格"的一方尽量成为被动关闭者,降低其 TIME_WAIT 压力(视业务/栈实现)。

序列号/确认号与去重、排序、确认

我面试常用"翻书"比喻:

能力 解决的问题 类比
序列号(seq) 去重与排序 页码防重排
确认号(ack) 成功到达的确认 勾选"已读"
窗口(win) 节流与并行度 读写节拍

发送端维护已发送未确认的数据集合,接收端通过累计 ACK 告知"我已经连续收到哪一位点前的所有字节"。


重传机制:超时重传与快速重传

  • 超时重传(RTO):发送后启动定时器,超时无 ACK 则重发;RTO 自适应基于 RTT 与抖动(通常 > RTT 的一定倍数)。
  • 快速重传:收到 3 个重复 ACK(如 ACK=101,101,101),判定某段可能丢了,提前重传,减少等待 RTO 的成本。

要点:

  • 重传报文的 seq 与原始相同,可能合并为更大段(取决于实现)。
  • 局部乱序也会触发重复 ACK,但不等同于丢包;拥塞控制会进一步介入(见下)。

滑动窗口与流量控制

  • 接收窗口(rwnd):接收端缓冲可用空间,通过报文通告给发送端,防止"接收方处理不过来"。
  • 发送窗口(swnd):发送端根据 min(cwnd, rwnd) 决定实际并发在途数据量。
  • 零窗口探测:若 rwnd=0,发送端定期发探测报文,等待窗口开放。

可视化(简略):

复制代码
|--- 已确认 ---|--- 已发送未确 ---|--- 可发送窗口 ---|
                ^ base            ^ nextSeq

拥塞控制:慢启动/拥塞避免/快重传/快恢复

  • cwnd:拥塞窗口,代表"网络可能承受的并发在途量"的猜测值。
  • 慢启动:从 1 MSS 开始指数增长,阈值 ssthresh 之前翻倍,之后线性增加(拥塞避免)。
  • 快重传/快恢复:
    • 3 次重复 ACK 触发:ssthresh = cwnd/2cwnd = ssthreshssthresh + 3*MSS(依实现),进入快速恢复,避免回到 1 MSS 的冷启动。
  • 超时:说明更严重拥塞,通常将 cwnd 置 1 MSS,重新慢启动。

保活机制与长连接

  • KeepAlive:长时间无数据时周期性发送探测包;若多次无响应,判定连接死亡并关闭。默认关/开与探测周期依 OS 而异,可配置。
  • 应用层心跳:例如 HTTP/2、WebSocket 自带 ping/pong,更灵活。

半连接队列、全连接队列与 SYN 攻击

  • 半连接队列(SYN 队列):收到 SYN,发送 SYN+ACK,等待第三次握手的 ACK。若超时未到达则过期剔除。
  • 全连接队列(Accept 队列):三次握手完成的连接,等待应用层 accept() 取走。
  • 防护思路:
    • SYN Cookies、缩短 SYN/ACK 重传与过期时间、增大队列。
    • 使用负载均衡/防火墙清洗异常 SYN 洪泛。

RST 的语义:什么时候会被动断开

  • RST 表示"连接非法/不存在或异常状态",常见触发:
    • 目标端口无进程监听;
    • 应用层提前关闭 socket,仍收到对端数据;
    • 抓包/半开异常导致状态机不同步。
  • 面试提示:用 RST 终止连接不会进入 TIME_WAIT(与 FIN 流程不同)。

常见高频面试问答(含易错点)

  1. 为什么是三次握手不是两次?
  • 需要确认"双方收发能力",并防历史连接的重放,占用资源。
  1. 为什么挥手要四次?
  • 关闭是单向的,两个方向分别 FIN/ACK。
  1. TIME_WAIT 为什么在主动关闭方?
  • 负责兜住最后 ACK 丢失与旧报文消散。
  1. 3 个重复 ACK 一定是丢包吗?
  • 不一定,可能乱序;但为降低时延会触发快速重传并调整拥塞窗口。
  1. rwndcwnd 谁说了算?
  • 实际可发窗口取两者较小值:min(cwnd, rwnd)
  1. 半连接队列爆了怎么办?
  • 开启 SYN Cookies、调大队列、缩短重试、前置抗 DDoS。
  1. 为什么 TCP 是字节流,UDP 是报文?
  • TCP 为可靠按序的连续字节,UDP 不保证顺序、丢失可见,保留消息边界。

抓包与排错清单

  • 观察三次握手:过滤 tcp.flags.syn==1 && tcp.flags.ack==0
  • 快速重传:看是否出现 3 次重复 ACK 与 Dup ACK 标记。
  • RTO 触发:同一 seq 的报文重发,时间间隔接近 RTO。
  • 零窗口:Window Size Value = 0 与周期性探测包。
  • 拥塞事件:[TCP Previous segment not captured][Retransmission]、窗口骤降。

Wireshark 过滤示例:

text 复制代码
# 仅看 TCP 握手
tcp.flags.syn==1 || tcp.flags.fin==1 || tcp.flags.reset==1
# 指定四元组
ip.addr==A && ip.addr==B && tcp.port in {PORT1,PORT2}

参考与延伸阅读

  • RFC 793、RFC 5681:TCP 规范与拥塞控制
  • 《Linux高性能服务器编程》《TCP/IP 详解 卷一》
  • Wireshark 官方文档与实践

相关推荐
BingoGo1 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack1 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
JaguarJack2 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo2 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack3 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理4 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
DianSan_ERP4 天前
电商API接口全链路监控:构建坚不可摧的线上运维防线
大数据·运维·网络·人工智能·git·servlet
呉師傅4 天前
火狐浏览器报错配置文件缺失如何解决#操作技巧#
运维·网络·windows·电脑
gihigo19984 天前
基于TCP协议实现视频采集与通信
网络协议·tcp/ip·音视频
QQ5110082854 天前
python+springboot+django/flask的校园资料分享系统
spring boot·python·django·flask·node.js·php