Theory · Network · TCP

TCP 三次握手与四次挥手

一条连接的全生命周期:SYN/SYN-ACK/ACK · FIN 交换 · 11 状态 · TIME_WAIT —— 连接管理(RFC 9293 Connection Management)

三次握手

双向同步 ISN 的最小可靠方案;SYN 消耗一个序号

四次挥手

全双工两方向独立关闭;被动方延迟关 → ACK/FIN 分离

TIME_WAIT

主动关闭方等 2×MSL(Linux 固定 60s)做可靠收尾

TCP 连接管理是网络面试的敲门砖,几乎每轮必问。这份 deck 按"状态机全景 → 握手 → 挥手 → TIME_WAIT → 内核队列 → 异常 → 实战 → QA"组织,所有结论对照 RFC 9293 和内核文档核对过,版本敏感点(tcp_tw_recycle、somaxconn 默认值)都标了内核版本。

Big Picture

11 个状态:一条连接的一生

TCP 连接管理状态机 TCP 11 个状态的迁移图:CLOSED 经 listen 或 connect 进入监听或 SYN-SENT,完成三次握手到 ESTABLISHED;主动关闭经 FIN-WAIT-1/FIN-WAIT-2 进 TIME-WAIT,被动关闭经 CLOSE-WAIT/LAST-ACK 直接关闭,同时关闭走 CLOSING。 ESTABLISH · 建立连接 TEARDOWN · 关闭连接 listen() connect() 收到 SYN 收到 ACK 收到 SYN+ACK 同时打开 close() 收到 FIN 收到 ACK 收到 FIN+ACK 收到 ACK 收到 FIN close() 收到 ACK 2MSL 超时(Linux 60s) CLOSED 初始态 LISTEN listen() 后 SYN-SENT 已发 SYN SYN-RECV 半连接 ESTABLISHED 双向数据传输 FIN-WAIT-1 主动关 · 等 ACK FIN-WAIT-2 等对方 FIN CLOSE-WAIT 等应用 close() CLOSING 同时关闭 TIME-WAIT 2MSL · Linux 60s LAST-ACK 被动方 FIN 已发
先给全景:握手占左边三步(CLOSED → SYN-SENT/SYN-RECV → ESTABLISHED),关闭占右边两条主路——主动方走 FIN-WAIT-1/2 → TIME-WAIT,被动方走 CLOSE-WAIT → LAST-ACK。读图的三条主线与两个不对称展开在下一页。

Big Picture · Reading Guide

三条主线 + 两个不对称

建立侧(图左)

被动打开:listen() 进 LISTEN → 收 SYN 进 SYN-RECV → 收 ACK 进 ESTABLISHED。
主动打开:connect() 进 SYN-SENT → 收 SYN+ACK 进 ESTABLISHED。

关闭侧(图右)

主动方:close() → FIN-WAIT-1 → FIN-WAIT-2 → TIME-WAIT(2MSL)→ CLOSED。
被动方:收 FIN 进 CLOSE-WAIT → close() 进 LAST-ACK → 收 ACK 直接 CLOSED。

两个不对称 + 罕见分支

TIME-WAIT 只属于主动关闭方;LAST-ACK 直接关闭、不等 2MSL。CLOSING 是同时关闭的罕见分支(虚线路径)。

图例:实线 = 正常路径;虚线 = 同时打开 / 同时关闭;蓝色填充 = ESTABLISHED 数据态。TIME-WAIT 与 SYN flood 的细节分别见后文对应页。

这页把状态机图读成三句话:建立两条线、关闭两条线、两个不对称。面试时先画图再顺着这三条主线讲,TIME-WAIT 为什么在主动方(谁先发 FIN 谁等 2MSL)和 LAST-ACK 的直接关闭是常追问点。

Handshake · Sequence

三次握手:报文与状态变化

三次握手时序图 客户端与服务端之间交换三个报文建立连接:SYN(seq=x),SYN+ACK(seq=y, ack=x+1),ACK(ack=y+1);客户端经历 CLOSED、SYN-SENT 到 ESTABLISHED,服务端经历 LISTEN、SYN-RECV 到 ESTABLISHED,随后进入双向数据传输。 客户端 Client 主动打开 active open 服务端 Server 被动打开 passive open CLOSED SYN-SENT ESTABLISHED LISTEN SYN-RECV ESTABLISHED ① SYN seq = x ② SYN+ACK seq = y, ack = x+1 ③ ACK ack = y+1 ESTABLISHED · 全双工数据传输 请求数据(如 HTTP) 响应数据(如 HTTP)
时序题答法:报文 + 状态 + 序号三要素。客户端 SYN-SENT,服务端 SYN-RECV,第三次 ACK 到达后双方 ESTABLISHED。三个报文各自的细节(序号消耗、选项协商、捎带数据)展开在下一页。

Handshake · Details

三个必考细节:序号、选项、数据

SYN 消耗一个序号

下次发送从 x+1 开始;FIN 同理占一个序号,纯 ACK 不占(RFC 9293 §3.3)

前两段协商选项

MSS、窗口缩放(WScale)、SACK-Permitted、时间戳,只在 SYN / SYN+ACK 中交换

第三段可携带数据

标准允许 ACK 捎带应用数据(TFO 更进一步,RFC 7413);服务端收到即完成建连

Linux 上 ss 看到的 SYN-RECV 就是半连接状态——半连接队列与 SYN flood 见后文「内核双队列」页。第三次 ACK 丢失时客户端已 ESTABLISHED、服务端仍 SYN-RECV,重发的是 SYN+ACK。

三个细节各自能引出追问:序号消耗连着 FIN/ACK 的差别,选项协商连着 MSS 与窗口缩放,第三段带数据连着 TFO。第三段 ACK 丢失的场景把「客户端已建连、服务端还在等」讲清楚,为后面全连接队列溢出页做铺垫。

Handshake · Why 3

为什么恰好是三次,两次不行吗?

本质:可靠地双向同步 ISN

  • 每个方向的 ISN 都要"提出(SYN)+ 确认(ACK)",共 4 个信息
  • SYN 与 ACK 可合并在同一段(SYN+ACK)→ 4 个信息最少用 3 段报文承载
  • 四次没必要:第二次报文天然可以捎带对客户端 SYN 的确认

两次为什么不行:历史(重复)SYN

  • 网络中滞留的旧 SYN 先于新连接到达服务端
  • 两次握手:服务端回 SYN+ACK 后直接建立连接,单方面在死连接上分配资源等待数据
  • 三次握手:客户端发现 ack 序号对不上(不是自己发的连接),回 RST 拒绝——服务端不建连

从"确认双方收发能力"推一遍

1

C → S:服务端收到 SYN ⇒ 确认「客户端发送能力 OK」

2

S → C:客户端收到 SYN+ACK ⇒ 确认「服务端收、发能力都 OK」

3

C → S:服务端收到 ACK ⇒ 确认「客户端接收能力 OK」——缺这一步,服务端不知道自己发的包客户端收没收到

RFC 9293 §3.4 / §3.5:三次握手解决的核心问题是"旧重复连接请求"(old duplicate connection initiations)。并非所有协议都强制三次(TCP Fast Open 借助 cookie 省一次 RTT),但标准握手 3 段是不引入额外机制时的最小可靠方案。

答题分层:先给一句话(最小可靠地双向同步 ISN + 防历史连接),再展开"4 个信息 3 段承载",最后讲历史 SYN 场景——没有第三次握手服务端会单方面建连。收发能力推导是备用讲法,面试官追问"三次各确认了什么"时用它。

Handshake · ISN

ISN 为什么不是从 0 开始的固定值?

生成算法(RFC 6528,并入 RFC 9293)

// ISN = 单调时钟 + 伪随机偏移
ISN = M + F(localip, localport,
            remoteip, remoteport, secret)

// M:32 位时钟计数,每 4μs +1(RFC 793 传统)
// F:密钥参与的安全伪随机函数
// Linux 实现:net/ipv4/secure_seq.c
//   对四元组+密钥做哈希,再叠加时间计数

理由一:防旧报文串扰

相同四元组的旧连接还有报文在网络中游荡时,随机化 + 时钟推进让新连接的序号窗口错开,旧数据不会被误认为新数据。固定从 0 开始则新旧连接序号空间完全重叠。

理由二:安全(防序号猜测攻击)

ISN 可预测 ⇒ 不在网络路径上的攻击者(off-path)能猜中序号,对已建立连接伪造 RST 或注入数据(1996 年 Mitnick 攻击)。RFC 1948 首次给出时钟+随机偏移方案,RFC 6528 升级为密钥化 PRF。

序号只有 32 位,传大文件会回绕,怎么办?

序号按模 232 回绕,靠"序号比较 + 时间戳选项(PAWS)"丢弃属于上一轮的旧段。这一块属于可靠传输主题,展开见 TCP 可靠传输与拥塞控制(待沉淀)。

ISN 是握手题的进阶考点。答出 RFC 6528 的公式和两个理由(防旧段、防猜测攻击)就够了;Linux 细节能提到 secure_seq.c 哈希加分。记住数字:时钟每 4 微秒加 1。

Teardown · Sequence

四次挥手:报文与状态变化

四次挥手时序图 客户端与服务端四个报文关闭连接:客户端发 FIN(seq=u),服务端回 ACK(ack=u+1) 进入 CLOSE-WAIT,期间可继续发送剩余数据,随后服务端发 FIN(seq=w),客户端回 ACK(ack=w+1) 后进入 TIME-WAIT 等待 2MSL 再关闭,服务端收到 ACK 后直接 CLOSED。 主动关闭方 先 close() 的一端 被动关闭方 后 close() 的一端 ESTABLISHED FIN-WAIT-1 FIN-WAIT-2 TIME-WAIT CLOSED ESTABLISHED CLOSE-WAIT LAST-ACK CLOSED ① FIN seq = u(消耗一个序号) ② ACK ack = u+1 剩余数据(被动方 CLOSE-WAIT 期间可继续发) ③ FIN seq = w ④ ACK ack = w+1 TIME-WAIT · 等 2×MSL(Linux 固定 60s)
时序题要点:报文 + 状态 + 谁等谁。主动方 FIN-WAIT-1 → FIN-WAIT-2 → TIME-WAIT;被动方 CLOSE-WAIT(等应用层 close)→ LAST-ACK → CLOSED。中间虚线是半关闭窗口:被动方收到 FIN 后还能继续发数据,这是四次之所以"四"的根本原因。最后一个不对称:TIME-WAIT 等待 2MSL,LAST-ACK 不等。

Teardown · Why 4

为什么挥手要四次?什么情况下变成三次?

根本原因:全双工

TCP 两个方向独立关闭。对方发 FIN 只说明"它不再发了",自己可能还有数据要发——ACK 先回,FIN 等应用层调 close() 再发,一来一回就是 4 段。

何时合并成三次

被动方无待发数据且应用立刻 close()(延迟 ACK 期间被合并)⇒ ACK 与 FIN 合成一段 FIN+ACK。Linux 下抓包最常见的正是"三次挥手"。

抓包注意

考官如果说"我抓包只有三次",答案是合并,不是四次挥手错了——四次挥手描述的是状态机语义(两个方向各关一次),不是固定报文数。

半关闭(half-close):只关一半

shutdown(fd, SHUT_WR) 只关写方向:发 FIN 后仍可读对方数据。典型用法:客户端发完请求就 FIN("我发完了"),服务端继续算、把响应全部写完再 FIN。四次挥手时序图中间的虚线数据段就是这个窗口。

close() 与 shutdown() 的区别

  • close():fd 引用计数减 1,减到 0 才发 FIN;同时关闭读写两个方向
  • shutdown():无视引用计数,立即触发 FIN;可只关一个方向
  • 多进程/多线程共享同一 socket 时,想立刻让对端收到 FIN 只能用 shutdown
这页应对"为什么是四次/我抓包怎么只有三次"的组合追问。核心:全双工 → 两方向独立关 → ACK 与 FIN 分离;合并条件是无数据+立即 close。close 与 shutdown 的差异是常被顺带问到的点。

Teardown · TIME_WAIT

TIME_WAIT:为什么等 2×MSL?

理由一:可靠地终止连接

最后的 ACK 是不可靠交付的——若它丢了,被动方停在 LAST-ACK 并会重传 FIN。留在 TIME-WAIT 的一端才能重发 ACK,把连接体面收尾。若直接关闭并复用端口,重传的 FIN 会打到新连接上。

理由二:让旧报文自然消亡

保证本连接的报文在网络中全部过期(去程 + 回程各一个 MSL),之后相同四元组的新连接不会收到旧幽灵报文,序号也不串扰。MSL = 报文最大生存时间,RFC 9293 建议 2 分钟,实现可权衡调小。

大量 TIME_WAIT 怎么办(短连接客户端场景)

  • 根治是复用连接:长连接 / 连接池(HTTP keep-alive、gRPC 复用)
  • tcp_tw_reuse=1 + tcp_timestamps=1:基于时间戳安全复用,仅对主动发起方向生效;内核默认 2(仅回环地址)
  • 扩端口范围 ip_local_port_range;监听端配 SO_REUSEADDR
  • tcp_max_tw_buckets 超上限直接销毁并告警——是兜底不是解法

版本敏感:别再背旧答案

  • Linux 的 TIME_WAIT 固定 60 秒TCP_TIMEWAIT_LEN,include/net/tcp.h),并不读 MSL 配置
  • tcp_tw_recycle 依赖按源 IP 排序时间戳,NAT 下误杀,Linux 4.12 已移除——老博客建议开它的一律过时
  • TIME_WAIT 在主动关闭方:让客户端先关或由 LB 分摊出口,可避免服务端堆积
TIME_WAIT 是本题的深水区。两条理由必须成对背:ACK 重传兜底 + 旧报文消亡。处置题先说根治(长连接),再说内核参数,最后抛 tcp_tw_recycle 已移除展示版本敏感度——这是加分项。

Implementation · Linux

内核里的两个队列:半连接与全连接

服务端内核握手队列 客户端 SYN 进入服务端内核的 SYN 队列(半连接,SYN-RECV 状态,受 tcp_max_syn_backlog 限制),第三次握手 ACK 到达后连接完成并移入 Accept 队列(全连接,容量为 listen backlog 与 somaxconn 的较小值),应用程序调用 accept 从队列取走连接。 SERVER KERNEL · 服务端内核 SYN SYN+ACK 握手完成 accept() 客户端 connect() SYN 队列(半连接) SYN-RECV · tcp_max_syn_backlog req1 req2 req3 Accept 队列(全连接) ESTABLISHED · min(backlog, somaxconn) conn1 conn2 应用程序 accept() 取走

半连接队列满

丢弃新 SYN;tcp_syncookies=1(默认开)时改发 SYN cookie,无状态完成握手

全连接队列满

第三次 ACK 被静默丢弃(客户端已 ESTABLISHED、服务端仍 SYN-RECV);tcp_abort_on_overflow=1 则直接回 RST

可观测

ss -lnt 的 Recv-Q / Send-Q = 当前全连接队列长度 / 容量;日志 "possible SYN flooding on port X" 常常是 accept 队列满

把握手落到内核实现:SYN 队列放半连接(SYN-RECV),完成三次握手进 accept 队列等应用 accept。容量两个公式:半连接看 tcp_max_syn_backlog(随内存伸缩,最小 128),全连接取 min(listen backlog, somaxconn),somaxconn 默认 4096(Linux 5.4+,之前 128)。应用 accept 不及时 → 全连接队列堆积 → 表现为连接超时。

Attack & Defense

SYN Flood 与 SYN Cookies

攻击原理

  • 海量伪造源地址的 SYN 打向服务端,永远不回第三次 ACK
  • 半连接(SYN-RECV)只能靠 SYN+ACK 重传自然老化(tcp_synack_retries 次、约 1 分钟),期间占满 SYN 队列
  • 正常用户的新 SYN 被丢弃 ⇒ 连接建立成功率骤降(DoS)
  • 标准攻防参考:RFC 4987(TCP SYN Flooding Attacks and Common Mitigations)

SYN Cookies:无状态握手

  • 思路:把连接信息编码进 SYN+ACK 的序号,服务端不为半连接分配任何内存
  • Cookie ≈ 5 bit 时间戳 + 3 bit MSS 档位 + 24 bit 四元组密钥哈希
  • 收到第三次 ACK 时用哈希验证,通过则按 cookie 重建连接参数
  • 代价:SYN+ACK 不缓存对方选项 ⇒ 窗口缩放、SACK 等协商丢失;SYN+ACK 也不重传

防御清单(自下而上)

  • tcp_syncookies=1(默认):队列满自动启用,正常流量零影响
  • 调大 listen backlog + tcp_max_syn_backlog(单纯调大只是提高攻击者成本)
  • 缩短半连接老化:tcp_synack_retries 调小
  • 上游:清洗中心 / 防火墙限速 SYN,伪造源地址过滤(BCP38)

面试加分点

  • 半连接队列满但日志只有少量 SYN_RECV ⇒ 瓶颈其实在 accept 队列(应用 accept 太慢)
  • syncookies 启用后,握手不依赖 SYN 队列 ⇒ 攻击者无法用内存耗尽服务端
  • cookie 方案与 TCP 选项协商冲突,高 BDP 链路(需要大窗口缩放)受影响
攻击面:利用"半连接要占内核资源且老化慢"。防御核心是 SYN cookies 的无状态思想——状态编码进序号、收到 ACK 再验证。代价(选项协商丢失)和误判(可能是 accept 队列满)是能拉开差距的细节。

Edge Cases

各阶段丢包会怎样?RST 何时出现?

丢失的报文双方行为关键参数 / 结果
SYN客户端重传 SYNtcp_syn_retries=6,指数退避,约 2 分钟(~131s)后放弃,connect 报超时
SYN+ACK双方各自重传:客户端重发 SYN,服务端重发 SYN+ACK服务端 tcp_synack_retries=5(约 1 分钟放弃);客户端 syn_retries 内重试
第三次 ACK客户端已 ESTABLISHED;服务端停在 SYN-RECV 重传 SYN+ACK客户端后续报文(数据本身带 ACK)到达可补完成握手;服务端放弃后发数据会收到 RST
FIN发送方重传 FIN重传由既有超时机制驱动,应用层无感
最后 ACK被动方停在 LAST-ACK 重传 FIN;主动方(TIME-WAIT)重发 ACK这正是 TIME_WAIT 存在的理由一;FIN-WAIT-2 孤儿超时 tcp_fin_timeout=60s

RST(异常终止)的常见触发

  • 连接不存在的端口:SYN 打到无监听端口 → 回 RST
  • half-open:对端崩溃/重启后,旧连接收到新报文 → 回 RST(区分 half-close:那是有序的半关闭)
  • accept 队列溢出且 tcp_abort_on_overflow=1
  • close 时接收缓冲区仍有未读数据 → 发 RST 而非 FIN;SO_LINGER(on, 0s)强制 RST 关闭

一张默认值速查(Linux man-pages / 内核文档)

  • tcp_syn_retries=6 · tcp_synack_retries=5 · tcp_fin_timeout=60s
  • TCP_TIMEWAIT_LEN=60s(硬编码)· somaxconn=4096(≥5.4)
  • tcp_abort_on_overflow=0(静默丢弃)· tcp_tw_reuse=2(仅回环)
  • 版本敏感参数先反问内核版本再下结论
丢包题的答题模板:先说谁处于什么状态,再说谁重传什么、重传几次、多久放弃。最容易答错的是 SYN+ACK 丢失——双方都在重传。RST 是"异常终止"信号,把四个触发场景记熟,half-open 与 half-close 的区别一定要分清。

Practice

实战:观察连接状态 & 排查 CLOSE_WAIT 堆积

# 状态总览(各状态连接数)
ss -s
# 按状态过滤:TIME_WAIT / CLOSE-WAIT / SYN-RECV
ss -ant state time-wait | wc -l
ss -ant state close-wait | wc -l
# 监听端口:Recv-Q=当前 accept 队列, Send-Q=容量
ss -lnt

# 抓握手/挥手/RST(过滤标志位)
tcpdump -i any -nn 'tcp[tcpflags] &
  (tcp-syn|tcp-fin|tcp-rst) != 0' port 8080

TIME_WAIT 多在主动关闭方;CLOSE_WAIT 多在被动方且语义完全不同。

CLOSE_WAIT 堆积 = 代码 Bug

  • 语义:对端已 FIN,本端内核回了 ACK,但应用一直没调 close()
  • 典型:HTTP client 忘了 resp.Body.Close();连接池里的死连接不清理;错误分支漏关 fd
  • 危害:fd 泄漏 → 进程 fd 打满 → 新连接 accept 失败
  • 排查:lsof -p PID 看打开的 fd;对照代码找"收到 EOF 后不关闭"的路径

对比:TIME_WAIT 堆积是协议行为(正常),CLOSE_WAIT 堆积是应用 Bug(必须修)。前者治"复用",后者治"关闭路径"。

Go 服务:用 http.Transport 连接池复用长连接(MaxIdleConnsPerHost);未读完 body 就 close 会触发 RST

排查题两大名场面:TIME_WAIT 多与 CLOSE_WAIT 多。一句话总结给面试官:TIME_WAIT 是协议设计(主动方等 2MSL),处置靠复用;CLOSE_WAIT 是应用忘了 close(fd 泄漏),必须修代码。工具侧 ss 优先于 netstat,ss -lnt 的 Recv-Q/Send-Q 能直接看 accept 队列压力。

Interview QA · 1/2

高频 QA(上)

Q1 · 为什么握手是三次?两次为什么不行?

双向同步 ISN防历史 SYN4 信息 3 段承载

每个方向的 ISN 都需要"提出+确认"共 4 个信息,SYN 与 ACK 可合并,3 段是最小承载。两次握手下服务端无法确认自己的 SYN+ACK 被收到,更致命的是旧重复 SYN 会直接建立死连接;三次握手中客户端校验 ack 发现不是自己的连接,回 RST 拒绝(RFC 9293 §3.4)。

Q2 · 第三次握手的 ACK 丢了会怎样?

SYN-RECV 重传synack_retries=5数据可补救

服务端停在 SYN-RECV,重传 SYN+ACK 共 5 次(约 1 分钟)后释放半连接。客户端已 ESTABLISHED,之后发的数据报文本身携带 ACK,到达即可补完成握手;若服务端已释放,客户端发数据会收到 RST。若开了 TFO/数据捎带场景另说,标准答案按上面三层展开。

Q3 · 挥手为什么四次?什么情况只有三次?

全双工ACK+FIN 合并半关闭

两个方向独立关闭:被动方收到 FIN 后可能还有数据要发,ACK 先回、FIN 等应用 close 时再发,共 4 段。被动方无数据且立即 close 时 ACK 与 FIN 合并为一段(延迟 ACK 下常见),Linux 抓包常见三次。语义上永远是"两个方向各关一次",报文数只是实现细节。

Q4 · TIME_WAIT 为什么存在?为什么在主动关闭方?

ACK 重传兜底旧报文消亡2MSL / Linux 60s

最后的 ACK 不可靠交付:主动方必须停留一段时间,在被动方(LAST-ACK)重传 FIN 时重发 ACK——理由一;同时等本连接报文全部过期,避免污染相同四元组的新连接——理由二。在主动方是因为它持有"最后一个 ACK"的责任。RFC 建议 2×MSL,Linux 固定 60 秒。

QA 按报文流顺序排。答题套路:先一句话结论,再展开状态与重传,最后补数字细节(synack_retries=5、约 1 分钟、60 秒)。Q2 注意"客户端数据可以补完成握手"这个反直觉细节。

Interview QA · 2/2

高频 QA(下)

Q5 · 客户端出现大量 TIME_WAIT,怎么治理?

长连接/连接池tcp_tw_reuse端口范围

根治是复用连接(HTTP keep-alive、连接池、gRPC 长连接)。内核侧:tcp_tw_reuse=1 + tcp_timestamps=1(默认 2 仅回环;仅对主动发起方向生效,NAT 安全);扩 ip_local_port_range;监听端 SO_REUSEADDR。tcp_max_tw_buckets 是兜底上限,超限直接销毁并告警,别当正常手段。tcp_tw_recycle 已于 Linux 4.12 移除,别再提。

Q6 · 服务端大量 CLOSE_WAIT 说明什么?

应用没 closefd 泄漏排查代码

对端已关闭、本端应用始终不调 close ⇒ fd 泄漏,最终 fd 耗尽。常见根因:HTTP 响应 body 忘 Close、连接池死链不回收、异常分支漏走关闭逻辑。排查:ss -ant state close-wait 定位对端与端口 → lsof 找 fd 归属 → 代码审"读对端 EOF 后的关闭路径"。与 TIME_WAIT 相反,这是必须修的 Bug 而非协议现象。

Q7 · SYN Flood 的原理与防御?

半连接耗尽SYN cookiesRFC 4987

伪造源地址海量 SYN 且不完成握手,半连接靠 SYN+ACK 重传自然老化(约 1 分钟),队列被占满后正常连接进不来。防御:tcp_syncookies(状态编码进 SYN+ACK 序号,收到 ACK 验证后重建,代价是选项协商丢失)、加大 backlog、缩短 synack_retries、上游清洗。注意"possible SYN flooding"日志可能实为 accept 队列满。

Q8 · close 和 shutdown 有何区别?RST 常见吗?

引用计数单向关闭SO_LINGER

close 只减 fd 引用计数,到 0 才发 FIN 且双向关闭;shutdown 无视计数立即发 FIN,可用 SHUT_WR 半关闭只关写方向,服务端"发完响应再 FIN"靠它。RST 常见触发:端口无监听、half-open(对端崩溃)、accept 队列溢出且 abort_on_overflow=1、close 时收缓冲有未读数据、SO_LINGER(1,0) 强制终止。

Q5/Q6 是一对:"TIME_WAIT 治复用,CLOSE_WAIT 治关闭"。Q7 记住 cookie 的编码思想和代价。Q8 把 close/shutdown/SO_LINGER/RST 串成一条"连接如何终止"的故事线,顺带区分 half-open 与 half-close。

References & Related

参考来源 & 相关知识点

参考来源(已逐条核对)

相关知识点(点击跳转 · 待沉淀项以虚线标注)

  • HTTP 与 Protobuf:底层原理与对比 — 本篇是它的传输底座:握手时延、1.1/2 队头阻塞的 TCP 根源
  • TCP 可靠传输与拥塞控制 待沉淀 — 序号/确认/重传/窗口,ISN 回绕与 PAWS 的展开
  • TCP Keepalive 与应用层心跳 待沉淀 — half-open 检测、连接存活与保活参数
  • I/O 多路复用(select/poll/epoll) — accept 队列的消费端,C10K 的另一面

本 deck 覆盖"连接管理"边界:建立(握手/ISN/选项)、终止(挥手/TIME_WAIT/RST)、内核队列与攻击面。数据传输过程不在本篇。

键盘操作: 翻页 · T 换主题 · S 演讲者模式 · O 总览。

所有结论对照 RFC 9293(现行 TCP 标准)、man-pages 与内核文档验证;版本敏感结论(tw_recycle 4.12 移除、somaxconn 5.4 默认 4096、tw_reuse 默认 2)均已标注。