HCIP备考提纲里同时出现“三次握手四次挥手”和“MTU测试”刚开始我是有点不解的。一个讲TCP状态一个讲IP分片怎么看都隔着好几层协议。直到我在实验环境里把中间链路MTU从1500调到1400抓包看到SYN报文里的MSS纹丝不动我才明白它们为什么总被放到一起连接管理决定了网络怎么“谈”MTU决定了数据怎么“走”。这篇文章就把这两个点串成一条线来写适合正在准备HCIP、或者做网络排错时总被“大包不通小包通”困扰的朋友。1. 为什么“握手挥手”和“MTU测试”在HCIP里是同一件事1.1 一个常见误区以为它们是互不相干的两个考点我见过不少备考HCIP的同学把三次握手四次挥手归到“TCP协议”把MTU测试归到“IP协议”然后分开背、分开刷题结果是笔试过了实验题一碰就露馅。真到了调设备的时候改两个路由器互联接口的MTUTCP会话立刻出问题抓包一看SYN报文里的MSS还是原来的1460大包被分片甚至被静默丢弃。这时候再回头翻协议栈才会意识到问题出在哪。这两个知识点从来不是两张皮。三次握手四次挥手解决的是连接什么时候建立、什么时候拆除TCP段的序号、状态、确认机制都是围绕这个展开MTU和MSS则解决连接建立之后每一个报文能装多少应用数据。换句话说一个管“会话状态”一个管“报文尺寸”但在HCIP的考试和真实网络排错里它们会撞到同一个点上TCP段的实际长度能不能塞进当前链路的MTU。1.2 把TCP连接管理和报文大小放进同一条链路里看TCP连接管理发生在传输层MTU问题发生在网络层和链路层但TCP段最终要靠IP封装才能转发表。IP层告诉你要经过的这条链路“最多能扛多少字节”TCP层就要据此决定“我的段该切多大”。这个决策的交汇点就是MSS——TCP在三次握手时通过SYN报文协商的最大段大小通常默认值是MTU减去IP头20字节和TCP头20字节。所以HCIP里经常把两者串起来问接口MTU从1500改成1400后TCP MSS应该变成多少答案不是1460而是1360。如果不理解这层关系就只能死记公式数值一变就不会。等到做MTU测试实验时你也会发现测着测着又回到了三次握手真正影响业务的不是Ping通不通而是SYN报文里的MSS选项有没有被正确改写。2. 三次握手三次报文交换背后的序列号与队列问题2.1 从抓包看懂SYN、SYN-ACK、ACK的语义三次握手的本质不是三次对称的问候而是双方互相确认“你能听到我我也能听到你”顺便把各自的初始序列号同步好。客户端发SYN携带自己的初始序列号比如 seqx服务器回SYN-ACK携带自己的初始序列号 seqy同时把客户端的x1作为ack返回客户端再回一个ACKacky1表示收到了服务器的序列号。前两次报文已经让服务器确认了客户端能发能收但客户端要确认服务器也能发能收必须等第三个ACK到达连接状态才会从SYN_RCVD变成ESTABLISHED。所以“三次”不是随便定的而是在不可靠网络上完成双向能力确认的最小报文数。抓包验证也很简单在PC上执行一条命令就能看到整个过程tcpdump -i eth0 -nn -S tcp[tcpflags] (tcp-syn|tcp-ack) ! 0最终会出现类似这样的三段交互10.0.0.10.50000 10.0.0.20.80: Flags [S], seq 3001 10.0.0.20.80 10.0.0.10.50000: Flags [S.], seq 8001, ack 3002 10.0.0.10.50000 10.0.0.20.80: Flags [.], ack 8002注意中间那条是S.同时带SYN和ACK很多人抓包后只盯着三个报文数量却忽略了第三个ACK里的 ack 值这个值一旦不对服务器会把连接挂到某一侧队列里等待重传。2.2 半连接队列、全连接队列和SYN Flood三次握手没完成时处于SYN_RCVD状态的连接会占在半连接队列里三次握手完成后连接进入全连接队列等待应用程序调用accept接收。如果队列被占满新连接无法建立表现就是客户端一直卡在SYN_SENT服务端抓包只看到SYN和SYN-ACK乱飞。最典型的攻击方式是SYN Flood攻击者只发SYN不回最后一个ACK把半连接队列塞满。HCIP里常考的应对手段是SYN Cookie它在SYN-ACK里把连接信息编码到Cookie里不在半连接队列中真实保存状态等客户端回过ACK后用Cookie重建半连接信息。这个机制在压力大的设备上默认开启但不能完全替代合理配置更不要把半连接队列和全连接队列设得无限大内存会被拖垮。2.3 同时打开握手报文不止三个的例外严格来说“三次握手”描述的是最常见的主动/被动建连场景。还有一种同时打开两端几乎同时给对方发SYN各自收到对方SYN后回SYN-ACK再互相确认报文中实际上出现了4次交互但状态机走的仍是握手流程。HCIP选择题偶尔会拿这个当干扰项问你是不是一定恰好三个报文。考试的时候只要记住核心判断标准不管SYN和ACK怎样排列关键永远是双方的序列号是否都被对端确认。如果是连接就建立成功不是就还在握手途中。把判断标准抓死就不容易被特殊场景带偏。3. 四次挥手真正的考点在TIME_WAIT和CLOSE_WAIT3.1 挥手为什么多一次这和半关闭有什么关系关闭TCP连接时主动关闭方先发FIN表示“我这边数据发完了”对端收到FIN后回ACK但这时候对端可能还有数据要发所以不会立刻发自己的FIN。等对端把剩余数据全部发完再回一个FIN主动关闭方收到FIN后再回ACK。因为“数据发完”和“关闭连接”是两个独立事件且收到FIN的一方通常先只确认不关闭所以最少要4次。如果两端同时关闭FIN和ACK可以合并报文数量会少一些。但HCIP考试默认主被动关闭场景不会拿同时关闭这种特例当主答案。你要理解的是半关闭的含义TCP允许某一方向先停止发送数据同时继续接收数据这种状态就是半关闭四次挥手正是为了完整覆盖两个方向的半关闭。3.2 TIME_WAIT的2MSL既保证可靠也变成性能问题主动关闭方在发出最后一个ACK后不能立刻进入CLOSED要先进入TIME_WAIT持续2MSL。原因有两个一是最后一个ACK可能丢失对方会重发FIN主动关闭方需要留在TIME_WAIT状态里重传ACK二是这条连接上的迟到报文可能还在网络中游荡如果端口立刻被新连接复用旧报文会被新连接误收导致数据错乱。2MSL不是随便定的是假设一个报文在网络中的最长生存时间乘以2保证一个方向的重传和另一个方向的迟到报文都能过期。HCIP考试爱问MSL默认值和哪个方向进入TIME_WAIT答案是主动关闭方。一台服务器如果频繁主动关闭连接TIME_WAIT会大量堆积占用本地端口和内存这就是性能问题的来源。3.3 协议栈参数怎么调才不算乱调看到大量TIME_WAIT不少人第一反应是改内核参数。net.ipv4.tcp_tw_reuse可以在新连接满足条件时复用TIME_WAIT状态下的端口但主要用于客户端出站连接而且依赖时间戳校验。在NAT网络后面使用要谨慎因为同一公网地址下多个内网设备的时间戳可能不满足递增要求复用后可能出现新连接收到旧报文的问题。tcp_tw_recycle就更不建议开了它在Linux 4.12内核后行为异常还会破坏NAT环境生产环境基本没有理由开启。实际项目里我更倾向于先看业务模型短连接太多就改成连接池或长连接让连接被复用而不是频繁新建。如果必须由服务端主动断开再考虑tcp_tw_reuse同时保留时间戳选项。检查TIME_WAIT数量用一条命令很简单ss -tan state time-wait | wc -l3.4 一条命令查清CLOSE_WAIT堆积的根因CLOSE_WAIT是收到对端FIN后本地应用还没调用close()时进入的中间状态。如果程序没处理对端关闭事件CLOSE_WAIT会一直堆积严重时连接数涨满新用户进不来。这种问题通常不是内核参数或网络设备配置能解决的是应用层没释放套接字。我在某次压力测试后就遇到过进程保持大量CLOSE_WAIT一开始以为是TCP参数问题后来抓包才发现对端早就发了FIN本地业务进程迟迟没有close。排查命令很简单先看状态再找进程ss -tan | grep CLOSE_WAIT lsof -i :8080HCIP实验里如果看到CLOSE_WAIT暴涨不要急着调TIME_WAIT参数先确认是不是应用层关闭逻辑有问题。这算是我的一个实操经验省得绕远路。4. MTU测试用Ping和抓包把分片问题测到明处4.1 MTU、IP分片和禁止分片标记三者的账要算清MTU是链路层对IP报文的最大承载能力以太网默认是1500字节但这个值不是处处一样。IP层发现报文超过下一跳MTU时可以把IP包切成多个分片前提是IP头里的DF标志为0如果DF为1则不允许分片发不下就直接丢弃通常会配合ICMP不可达报文通知源端。账要算清楚一个ICMP Echo请求的总长度是20字节IP头加8字节ICMP头加数据长度。在MTU为1500的链路上不触发分片的最大数据长度是1472字节。所以执行ping -M do -s 1472能通执行ping -M do -s 1500就不通后者总长1528字节已经超过1500同时在DF置位下会被丢弃。多出来的28个字节就是两个协议头的开销。4.2 不同系统下的MTU探测命令不同操作系统Ping参数不同但逻辑完全一样。Linux下用-M do强制DF-s指定数据长度Windows下用-f强制DF-l指定缓冲区长度。两个平台的等价命令是# Linux ping -M do -s 1472 10.0.0.2 # Windows ping -f -l 1472 10.0.0.2如果1472通、1500不通说明本段MTU大概率就是1500大包要么被分片要么被丢弃。要测完整路径可以按1. 常见的链路MTU从1500、1492、1400、1280往下二分法试每次加28字节的总开销。但这个办法只能测出端到端可用的最大报文长度无法定位是哪一个中间节点卡的所以需要配合逐跳探测。4.3 路径MTU发现和那个容易被忽略的ICMP报文路径MTU发现的思路是发送端把DF置1发一个大包中间路由器如果发现发不下就返回ICMP类型3代码4同时携带它自己的下一跳MTU源端收到后把报文大小调小重新发送。整个过程听着很顺但有个致命弱点中间设备一旦把ICMP过滤掉源端永远收不到“发不下”的通知只能一直重发大包形成黑洞。这是MTU测试里最典型的坑。排查MTU问题时要先确认中间防火墙或ACL有没有放行ICMP不可达否则你看到的Ping结果和真实业务流量完全是两回事。Linux下用tracepath做逐跳MTU探测很直观它会尽量利用DF和ICMP反馈Windows的tracert不会自动探测MTU不要混用。4.4 隧道封装让MTU缩水的常见计算只要加隧道封装MTU一定会下降。比如GRE封装要加外层IP头和GRE头IPsec封装还要再加认证和加密开销。物理链路MTU是1500时隧道接口往往只能配置1476或更小否则隧道口出来的报文超过物理链路MTU照样分片。计算时用减法别用加法。从协议栈最外层开始1500减去外层IP头20减去GRE头24得到1456。如果隧道里承载的是TCP业务TCP MSS还要再减20字节的TCP头实际可用MSS是1436。HCIP实验里喜欢给一张表让你算这个数原理就是一层层减。把这条逻辑记牢比背具体数值管用得多。5. 在HCIP实验环境里完整跑一遍MTU和MSS联动测试5.1 实验拓扑与预期目标我用的模拟拓扑很简单PCA连接R1R1连接R2R2连接PCBR1和R2之间的链路模拟一条MTU受限的广域网链路。目标分三步走先抓正常TCP握手记录MSS基线然后把R1-R2链路接口MTU调小观察大包连通性和分片变化最后通过TCP MSS钳制恢复传输效率并抓包验证。这个实验能直观回答一个HCIP高频问题为什么TCP已经协商好MSS中间链路MTU变小后业务还是会卡因为MSS协商只发生在两台终端之间中间路由器没法修改它除非特意做钳制。不亲眼看一次分片很难真正记住这个结论。5.2 第一步不调MTU先抓正常TCP的MSS实验最开始R1和R2互联接口MTU保持1500。在PCA上访问PCB的HTTP服务同时在PCA侧抓包能看到三次握手里SYN报文的MSS选项是1460。这是标准以太网链路的预期值1500减20字节IP头再减20字节TCP头。这个过程是基线后面所有判断都拿它对照。抓包时注意过滤条件不要只看三条报文就结束MSS选项藏在TCP头里需要展开TCP协议树才能看到。用命令行抓包可以用tcpdump -i eth0 -nn -S tcp[tcpflags] tcp-syn ! 05.3 第二步把中间链路MTU调小观察分片与连通性变化在R1和R2的互联接口上把MTU改成1400。这时候再去PCA上执行带有DF标志的Ping数据长度超过1380之后会因为超过MTU 1400而被丢弃。如果Ping不带DF报文会被R1拆成多个IP分片从抓包里能看到两个IP报文共享同一个ID偏移量不为0。关键现象是PCA发出的TCP SYN里MSS依然是1460。因为PCA只知道自己网卡MTU是1500它并不知道中间的R1-R2链路已经变成1400。MSS协商是端到端行为不经过中间链路感知所以这时候TCP业务必然出问题要么分片要么因为DF被丢弃触发PMTUD黑洞。这个步骤就是整套实验的核心HCIP考的就是这个认知。不看中间链路只看两端MSS根本发现不了问题。5.4 第三步用TCP MSS钳制消除分片抓包验证结果消除分片的正确做法是在中间设备上做TCP MSS钳制。在R1或R2的入接口方向把经过的TCP SYN报文里的MSS选项改写为1360。1400的MTU减去20字节IP头再减去20字节TCP头正好是1360报文总长度就不会超过链路MTU。配置思路是修改靠近终端一侧的接口让终端在握手阶段就收到一个更小的MSS通告。我一般会在路由器的接口视图下做类似这样一条命令tcp adjust-mss 1360不同厂商命令位置略有差异但原理相同。配置完成后重新抓包SYN报文里的MSS已经变成1360后续大数据包不再分片大包连通性恢复。5.5 实验做完后踩到的几个坑第一个坑是抓包点位置。分片发生在R1的出方向如果在PCA侧抓包只能看到原始大包看不到中间链路的分片结果。要看真实分片就得在R1和R2之间抓包或镜像端口。第二个坑是接口MTU改完老连接还带着旧MTU参数抓包结果很混乱需要等TCP连接超时释放或者重启客户端会话。第三个坑是防火墙过滤ICMP如果实验里模拟了防火墙过滤掉ICMP不可达后带DF的大包会无影无踪需要先用iptables -L之类确认规则。这些坑并不是HCIP考试内容本身但都是真实排错里绕不开的细节。6. 考场内外的排查清单与个人体会6.1 一张速查表问题状态、命令、处理思路现象优先检查参考命令三次握手停留在SYN_SENT半连接队列是否满、防火墙是否拦截SYNss -ant | grep SYN、netstat -s大量TIME_WAIT主动关闭方参数配置、短连接模型ss -tan state time-wait | wc -l大量CLOSE_WAIT应用层是否未关闭套接字ss -tan | grep CLOSE_WAIT、lsof大包不通小包通链路MTU是否过小、ICMP是否被过滤ping -M do -s 1400、tracepathTCP传输慢且抓包有分片TCP MSS与链路MTU不匹配抓SYN里MSS选项、tcp adjust-mss隧道业务大包黑洞隧道封装开销未扣减到MSS从物理MTU逐层减封装头这张表是我做实验时总结出来的不是HCIP官方清单但能帮助你把状态类问题和报文大小类问题分开定位。笔试里看到状态迁移、Time wait值、分片偏移这类题目对应到表里的场景反应会快很多。6.2 我的一点体会不要背状态迁移图要去抓一次包我见过太多人把TCP 11种状态背得滚瓜烂熟到实验环境里看到状态却对不上号。三次握手四次挥手看起来是协议流程题本质是抓包题。在实验环境里搭两台路由器两台PC抓一次建立连接、再抓一次关闭连接把SYN、SYN-ACK、ACK、FIN、TIME_WAIT的报文顺序和状态变化对应起来比背什么都管用。MTU测试也是一样。学会用Ping二分法再学会抓包看MSS选项比背十个参数值都值钱。我每次排查MTU问题都先问自己三件事这条链路有没有人改了接口MTU中间设备有没有把ICMP不可达过滤掉两端协商的MSS和链路MTU减法结果是不是同一个值把这三个点抓住单机MTU测试、路径MTU发现、MSS钳制这些知识点自然就能串成一条完整的排查链路。这也是我把“三次握手四次挥手”和“MTU测试”放在同一份备考清单里的原因它们本来就是一个网络工程师在处理连接问题时的两面。