ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

TCP与UDP协议详解:从报文结构到可靠性机制

TCP与UDP协议详解:从报文结构到可靠性机制 1. 为什么说学网络协议TCP和UDP是绕不开的两扇门先讲个我自己的经历。大二那年第一次翻开谢希仁的教材看到TCP和UDP那一章我以为是两个并列的协议背一背区别就能过关。结果期末考试第一道大题就让画TCP三次握手的状态迁移图第二道题直接给了一个UDP报文让拆字段。那会儿我才意识到TCP和UDP不只是两个协议名字它们是理解整个IP网络如何为应用提供服务的两把钥匙。后来工作了用iperf3给服务器做压力测试、用Wireshark抓包排查线上延迟再回头看大学教材才发现当年死记硬背的很多东西其实在真实环境下全都能一一对照上。这也是为什么我现在逢人就建议别急着背面试八股先把TCP和UDP的底层逻辑真正吃透后面的三次握手、四次挥手、滑动窗口、拥塞控制全都是顺理成章的事。这篇文章不打算做成教科书复读机。我会从拆报文的角度出发讲清楚TCP和UDP各自的设计哲学然后结合iperf3打流、抓包分析、编程实战这些具体场景把协议栈里那些一知半解的概念掰开揉碎。无论你是刚学计算机网络的学生还是准备面试的求职者又或者已经上手socket编程但老出问题的开发者这篇文章应该都能帮你把碎片补成整图。有两件事先说明。第一我会用大量的生活类比来讲原理但类比只是拐杖真正的落脚点还是协议字段和状态机本身。第二全文会穿插一些实操向的内容比如用iperf3测UDP丢包、用tcpdump看TCP重传这些命令你最好亲手跑一遍——看书十遍不如抓包一次。2. UDP的报文结构拆解——四平八稳的快件明信片2.1 八个字节能说明什么很多初学者看到UDP报文头只有8个字节第一反应是这也太简陋了吧。但恰恰是这种简陋成就了UDP的不可替代性。我们先看这8个字节是怎么组成的。UDP报文头的固定部分是四个字段每个字段占2个字节字段字节数作用源端口2标识发送方的应用程序目的端口2标识接收方的应用程序长度2整个UDP报文头部数据的字节数校验和2检测传输过程中是否出现比特错误这个结构简单到什么程度呢它甚至连这个报文属于哪条连接这样的信息都没有——因为UDP压根不维护连接状态。每个UDP报文都是一个独立的快递包裹寄出去之后发件人不会收到签收回执也不关心包裹中途是否被拆开或者丢掉。我用明信片来类比UDP再合适不过。你写好地址贴上邮票丢进邮筒后面的事情就跟你无关了。明信片的好处是什么寄起来快、成本低、不用等回执。坏处是什么可能丢、可能乱序、内容被别人看了你也不知道。这就是UDP的全部哲学能发就发发完拉倒。2.2 校验和计算里藏着的一个细节UDP校验和的计算方式经常被教材一笔带过但它其实埋了一个特别容易在考试和面试里被挖的坑。计算校验和之前发送方会在UDP报文前面加一个伪头部这个伪头部包含源IP地址、目的IP地址、协议号UDP是17和UDP长度。伪头部的存在意味着UDP的校验和不仅能检查UDP报文本身有没有比特翻转还能检查IP地址在传输过程中有没有被篡改。这就是伪字的意思——它不是UDP报文的真实组成部分只参与计算不参与传输。我见过不少同学在实现UDP协议栈的时候因为漏掉伪头部导致本机发送、本机接收一切正常一旦跨主机通信就疯狂丢包。排查半天最后发现是校验和永远算不对按接收方的视角来看每个报文都是坏的直接丢弃。这个坑我在后面讲协议栈实现的时候还会再提一次因为它真的很容易被低估。2.3 长度字段为什么明明能算出来还要显式携带有人会问UDP长度字段不就摆在IP层已经知道了吗IP报文头里已经包含了整个IP数据报的长度而IP头部长度也是已知的拿总长度减去IP头部长度不就得到UDP报文长度了吗何必再传一遍答案是为了让UDP成为一个自包含的协议。IP层可能分片可能填充UDP层并不完全信任IP层给自己转述的结果。长度字段的存在让UDP接收方可以直接从报文里获知这段数据有多少字节是属于我的哪怕IP层做了某些加工UDP仍然能够正确解析自己的边界。这种每层都把自己那点事管清楚的设计哲学在TCP里体现得更极致后面讲到TCP头部时你能看到TCP的头部字段多得让人头皮发麻。3. TCP头部的核心字段——从一次抓包开始讲3.1 一个真实TCP报文里到底藏了什么如果你用Wireshark抓一个HTTP请求的包点开TCP段那一层会看到一长串字段。初学者看到源端口、目的端口、序列号、确认号、数据偏移、保留位、标志位、窗口大小、校验和、紧急指针再加上一堆可选项瞬间就懵了。我当时自己学的时候用了最笨也最有效的一种方法只关注六个标志位即URG、ACK、PSH、RST、SYN、FIN。因为三次握手、四次挥手、连接重置、数据推送全部靠这六个比特位表达。理解TCP本质上是理解这套标志位如何组合出完整的连接生命周期。3.2 序列号和确认号漏掉任何一点都会绕晕序列号和确认号是TCP最核心、也最容易让人绕晕的两个字段。我先抛一个结论TCP传输的不是离散的数据包而是一个字节流。什么叫字节流想象你有一根无限长的水管发送方把数据一个字节一个字节地灌进去TCP负责把这个水管里的水切成一桶一桶地运到对端然后对端按顺序把桶里的水倒进自己的水管。序列号标记的是我这个桶里装的水是整根水管从第几个字节开始的确认号表示的是我期望对端下一个桶从第几个字节开始装。举个具体例子。发送方要发一串HELLO WORLD第一个字节是H。那么这个TCP段的序列号可能是1000不是0因为初始序列号是一个随机值数据区装上HELLO共5个字节。对端收到后回复ACK确认号是1005表示我已经正确收到序列号1000到1004这5个字节你下一个段从1005开始发给我。网上很多文章喜欢画三次握手的图把SYN和ACK两个标志位画得明明白白但从不解释为什么第二次握手要同时带SYN和ACK。其实道理就在字节流里第一次握手客户端发SYN携带的序列号假设是x第二次握手服务端回SYNACK它的SYN表示我也要建立这条连接我的初始序列号是yACK则表示我收到了你的x你的下一个字节该从x1编号了。两个信息拼在一个包里节约一次RTT这就是TCP的效率。3.3 窗口大小与滑动窗口TCP的手头余粮思想TCP头部里有一个2字节的窗口大小字段最大值65535。这个字段表示的是接收方当前还有多大的缓冲区能收数据。发送方必须盯着这个数字发数据不能盲目地把水管里的水全倒给对端。滑动窗口机制用一句话概括发送方维护一个可发送窗口窗口大小取接收方通告的窗口和本地拥塞窗口中的较小值。接收方的窗口解决的是对端处理不过来的问题拥塞窗口解决的是整条网络链路可能堵车的问题。两个窗口是两把尺子一个量对方一个量路况。我在实际排查慢速传输问题时见过太多次这样的情况延迟很高带宽很大CPU占用很低所有指标看起来都没问题但传输速率上不去。最后抓包发现接收方通告的窗口值一直在减小原因是接收方的应用层处理速度跟不上缓冲区被占满。这时候要解决的压根不是网络问题而是应用层的消费速度。3.4 十三个字节的保留区和可选项——别急着跳过TCP头部除了固定20字节后面还有可选项区域。最常见的可选项是MSS最大报文段长度、时间戳、窗口缩放因子、选择性确认SACK。很多教材把这部分当扩展内容略过但我想说这几个可选项恰恰是TCP性能优化的主战场。举一个例子窗口缩放因子。前面我说窗口大小字段最大65535如果不用缩放因子TCP的单条连接在带宽很高的链路上就达不到理想的吞吐量。想象一下往返时延是50毫秒窗口只有64KB那发送方每秒最多也就传输1.28MB左右的流量换成百兆网络都不够塞牙缝的。窗口缩放因子扩展让窗口可以按2的N次方缩放才撑起了今天万兆网卡上的TCP吞吐。还有个SACK选项专门处理多个包丢失的恢复。没有SACK的时候发送方只能通过累积确认猜测对端丢了哪几个包一旦中间有包丢了可能要从丢包前的位置开始全部重传效率极低。有了SACK接收方可以明确告诉发送方我这边的数据空洞在哪个区间发送方只需要精确补发空缺段即可。这个机制在互联网高丢包环境下是TCP保命的底牌。4. 三次握手与四次挥手——从状态机角度彻底搞懂4.1 为什么一定是三次握手不能是两次TCP三次握手的流程几乎每个学网络的人都能背出来SYN - SYNACK - ACK。但为什么不能是两次很多人其实没有真正想明白。核心原因有两条。第一条是防止历史连接的干扰。考虑这样一个场景客户端先发起了一个连接请求A因为网络阻塞迟迟没到客户端超时后发起了一个新连接请求B。如果只是两次握手那么当A最终到达服务端时服务端会直接同意并建立连接但客户端已经不要这条旧连接了这就会造成服务端白白维护一个废连接。三次握手让客户端有机会在第三步确认这是我当前发起的那条连接一旦发现序列号对不上可以立刻发RST把这条历史连接清掉。第二条原因是同步双方的初始序列号。握手阶段的核心目的之一是交流ISN初始序列号这个序号一旦不一致、不互通后续的字节流确认就是空中楼阁。三次握手确保双方都确认了彼此的初始序列号谁也不会误解数据编号。这两年考研408的题目里我注意到特别喜欢考查这样一个变体客户端发SYN后如果服务端回的是RST客户端应该如何处理。背后的考点恰恰是防止历史连接这一层思想——如果客户端收到一个跟自己的SYN不匹配的SYNACK就直接发RST拒绝这个连接。4.2 四次挥手的本质是双方各自断开四次挥手的流程是FIN - ACK - FIN - ACK很多人背完就忘。我换个角度给你讲TCP连接是全双工的数据可以双向独立传输。因此关连接这件事也必须双向独立。第一次挥手主动关闭方说我不再发数据了发FIN。第二次挥手被动关闭方回一个ACK表示我收到你不再发数据的通知了。但此时被动方自己还有可能要继续发数据所以它不能立即发FIN要等自己的数据发完。等它把剩余数据发完再发FIN这就是第三次挥手。主动关闭方收到FIN后回ACK这就是第四次挥手。这里有一个容易踩坑的状态TIME_WAIT。主动关闭方发送最后一次ACK之后并不会立刻进入CLOSED状态而是要等待2MSL两倍报文最大生存时间。为什么等这么久一是确保最后这个ACK能到达对端——如果这个ACK丢了对端会重发FIN如果主动方已经关闭了重发的FIN就没人应答对端就会一直卡在LAST_ACK状态。二是让这条连接上所有迟到的、乱序的报文在网络中自然消亡避免污染下一次使用相同四元组的新连接。4.3 连接建立与关闭中最常见的两个实测问题实际做服务端开发的时候我碰到最多的两个问题都跟握手挥手有关。第一个是服务端出现大量TIME_WAIT状态的连接。原因通常是短连接服务中服务端主动关闭连接每个关闭都要经历TIME_WAIT。解决思路有三个方向一是让客户端主动关连接把TIME_WAIT甩给客户端二是开启SO_REUSEADDR允许服务端在TIME_WAIT状态下复用端口三是升级到长连接减少连接建立和关闭的频率。我在Java后端项目里用过Netty做长连接压测TIME_WAIT问题的处理直接决定了能支撑多少并发连接。第二个是客户端连不上的时候第一时间要看是不是服务端卡在SYN_RCVD状态。SYN_RCVD是半连接状态服务端发了SYNACK但没收到客户端的最终ACK。如果服务端有很多SYN_RCVD通常意味着客户端收到SYNACK后失踪了。原因可能是客户端防火墙拦截了那个SYNACK也可能是服务端开启了SYN Cookie但客户端不支持对应的TCP选项。排查时用netstat -antp看状态分布一般能快速定位问题出在哪一侧。5. 可靠性机制的深水区重传、拥塞控制与保活5.1 超时重传与快速重传别让包白白走冤枉路TCP的可靠性基石之一是重传。发送方发出去一个段会启动一个计时器如果超时还没收到这个段的ACK就重新发送。这个超时时间RTO不能是固定的因为网络延迟一直在变。TCP用指数加权移动平均来估算RTT再结合RTT的方差计算出RTO。用大白话说就是我根据历史上每次往返时间估算下一次往返大概多久再留一些富余量做超时判断。快速重传则是另一个机智的设计。如果发送方连续收到三个重复的ACK就认为某个段丢了立刻重传不用等超时。为什么三个ACK能说明问题因为接收方每收到一个乱序段都会重复ACK自己最后一个有序接收的段。连续三个重复ACK说明排在那个段后面的数据已经陆续到了那个段很可能是真丢了而不是延迟。5.2 拥塞控制的四个阶段用一条山路来理解拥塞控制是TCP里最考验理解的机制也是面试官最爱追问的部分。我用一条山路的比喻来帮你建立直觉。设想你开着一辆货车在山路上送货路况未知。你一开始不敢开太快先以1个单位的速率试试水确认道路通畅后每过一个往返周期就把速率翻倍这叫做慢启动——名字虽然叫慢启动但增长速度其实是指数级的。速率涨到一个阈值ssthresh附近时你就不再翻倍了而是每次只增加一点这叫拥塞避免。如果你在半路遇到堵车触发丢包重传就立刻把速率掉下来轻则减半快速恢复重则直接从1重新开始超时重传。为什么要有慢启动和拥塞避免两阶段因为慢启动负责在连接刚建立、完全不了解路况的时候快速试探拥塞避免则负责在接近道路容量上限时细嚼慢咽。真正的高手还会关注一个指标带宽延迟积。当吞吐量接近带宽延迟积时继续盲目涨窗口不仅没有收益反而增加排队延迟和丢包风险。5.3 tcpdump实测如何抓到一个真实的超时重传纸上谈兵没意思我建议你亲手做一次重传观测实验。原理很简单用tc命令人为给网卡加上丢包和延迟再用tcpdump抓包看TCP重传标志。先模拟5%的丢包率和200ms延迟sudo tc qdisc add dev eth0 root netem loss 5% delay 200ms然后在两个终端分别起一个服务端和客户端用iperf3打流iperf3 -s iperf3 -c 127.0.0.1 -u -b 10M -t 10同时开Wireshark或者tcpdump抓包sudo tcpdump -i eth0 -nn tcp port 5201观察抓包结果时重点过滤TCP分析选项里的TCP Retransmission标记。你会看到Wireshark会用红色高亮标记重传包而且重传包的序列号往往和某个已经抓到的段重复。这个实验做完你对重传的理解会比看十遍教材都深刻。测试结束后记得清理规则sudo tc qdisc del dev eth0 root5.4 应用层心跳 vs TCP Keep-Alive谁才是保活的正主TCP头部没有也没办法有心跳字段但TCP确实提供了一个可选的保活机制叫Keep-Alive。默认情况下Linux的TCP Keep-Alive每2小时探测一次空闲连接探测不到回复后每75秒重试一次最多重试9次。看到这组默认参数你应该明白TCP Keep-Alive的设计初衷根本不是为应用层服务的。它只是用来清理那些长时间没有数据交换的半死连接防止系统资源被僵尸连接拖死。真正的高可用系统几乎都是自己在应用层做心跳包比如每10秒发一个PING连续三次没回就判定对端死了主动重连。我在做分布式微服务的时候对这一点体会特别深。服务间的长连接如果只依赖TCP Keep-Alive一次断网可能要几个小时才能被发现这在生产环境是不可接受的。后来我们统一在业务层做心跳配合断线重连才能做到秒级感知故障。所以说保活这件事TCP只能保底线业务等级的保护要给应用层自己来做。6. UDP和TCP的实际脾气对比——以及选型该听谁的6.1 从丢包率、乱序、吞吐三个维度实测UDP和TCP的区别网上随便一搜就有一堆表格但表格只告诉你UDP不保证可靠却没告诉你UDP在某些场景下反而比TCP更稳。我用iperf3实测一次给你看。在本地回环接口上先测TCP吞吐iperf3 -c 127.0.0.1 -t 10我自己的机器上TCP打了大概9.5Gbps几乎接近万兆上限。接着测UDPiperf3 -c 127.0.0.1 -u -b 10G -t 10UDP打流的时候不关心对端能不能接住它只管疯狂往发送缓冲区丢数据报。实测结果很有意思发送端报告发送了巨量报文但接收端实际收到的报文远小于发送量丢包率动辄二三十个点。原因很简单本地环回虽然路况好但UDP没有拥塞控制发得快了照样会把接收缓冲区挤爆挤不进去的报文就直接被内核丢掉。再把网络换成真实的局域网掉包率会更高。为什么UDP发送端不会因为丢包而降低速率它一如既往地以10Gbps的速率灌数据交换机缓存一旦溢出丢包率会呈雪崩式上升。6.2 什么时候该用UDP什么时候该用TCP这里我给一份基于实际生产经验的选择清单不限于考试考点但绝对实用。场景推荐协议原因Web页面、接口调用TCP完整性优先页面少传输几KB数据但必须完整文件传输、邮件TCP哪怕慢也不能丢字节域名查询DNSUDP单次查询大小极小追求低延迟失败可以重试视频直播、语音通话UDP丢失一帧声音画面可以容忍但延迟不可容忍游戏位置同步UDP启动快、无重传、实时性优先丢包靠插值糊弄过去物联网传感器上报UDP数据频繁但单包小可丢旧保新避免TCP重传堆积延时有个场景我特别想提醒你金融交易通道、设备控制指令这种绝不能丢但又需要极低延迟的场景不要一拍脑袋就选UDP。更成熟的思路是使用UDP传输但在协议栈上层自己实现序列号、确认、重传和乱序缓冲。QUIC协议就是这条路线的教科书案例它把TCP的可靠性逻辑搬到了用户态同时保留了UDP的低延迟优势并且解决了TCP队头阻塞的老大难问题。6.3 TCP的队头阻塞问题一个常被忽略的软肋讲TCP的缺点时如果只盯着慢和重传浪费带宽那还是浅了。TCP真正被很多人忽略的软肋是队头阻塞。什么叫队头阻塞TCP是字节流协议它要求数据严格按照序列号顺序交付给应用层。假设发送方发了一个窗口内的5个段第2个段丢了第3、4、5个段都到了。接收方为了保持有序会把3、4、5先存在缓冲区不交付给应用层同时反复发送ACK请求重传第2段。即便这个窗口里的其他数据早就到了应用层也只能干等着。在HTTP/1.1时代由于每个请求各自占用一条TCP连接这个问题被掩盖了不少但在HTTP/2多路复用一条连接传多个资源时队头阻塞的影响立刻放大——一个包丢了后续所有资源都得排队。这也是为什么Google要搞QUIC因为QUIC在一条连接上划分了多个独立的流每个流都有自己的序列号空间一个流的丢包不会阻塞其他流。理解了这一点你对为什么TCP有时反而不如UDP适合直播的理解就是降维级别的了。6.4 UDP调试工具给排查问题带来的便利工作中最常被忽略的一类工具是UDP调试工具和打流工具比如netcat、iperf3配合UDP模式、专门的UDP客户端模拟器。我自己就遇到过线上UDP组播服务收不到数据的问题排查过程全靠这些工具。第一步用nc确认本地端口是否能接收nc -u -l 12345另外一台机器上发送echo hello | nc -u 目标IP 12345如果收不到先用tcpdump看UDP报文是否到达网卡sudo tcpdump -i eth0 udp port 12345如果网卡能看到包但程序收不到基本可以断定是防火墙或路由问题。这一套组合拳能帮你把程序Bug和网络环境问题快速分离而不是一头扎进代码里瞎调。这种排查思路远比记住UDP协议里每个字段更重要。7. 学习资源配置指南——教材、网课、刷题、实操怎么组合7.1 教材怎么读谢希仁、王道、自顶向下三选一市面上的计算机网络教材琳琅满目我经常被问到底买哪本。我的看法是主攻考研408的王道配合谢希仁是标配。王道把考点归纳得非常清晰适合应试谢希仁的教材胜在体系完整很多概念的原理解释比王道更展开。但如果你是为了理解网络本身而学不是奔着考试去的那《计算机网络自顶向下方法》会更对你的胃口。自顶向下这本教材的思路是先用应用再谈原理。它从HTTP、DNS这些你实际用过的东西讲起再一层层往下钻进传输层、网络层这个路径对自学者极其友好。相比之下谢希仁教材更偏向自底向上从物理层一点点往上讲虽然严谨但对初学者就是一座大山。还要提一句湖科大教书匠这位UP主。他的视频以动画演示为主把三次握手、滑动窗口这些抽象概念用非常直观的动画呈现出来强烈推荐给任何觉得光看书看不进脑子的人。他讲TCP状态迁移的那几期哪怕你已经工作了回头看一遍也能把旧知识重新激活。7.2 八股文与面试题的正确打开方式各大社区的计算机网络八股文合集我建议你不要一上来就背而是先问自己三个问题三次握手为什么不能是两次四次挥手为什么要等2MSLTCP为什么需要拥塞控制如果这三个问题你都能用自己的话一个例子解释清楚那面试题基本难不倒你。一个比较好的训练方法是把面试题当定理自己去证明。比如有人问TCP和UDP的区别先别急着从面向连接vs无连接开始背而是从应用场景反推视频会议为什么选UDP因为延迟敏感、可以容忍轻微花屏。网页浏览为什么选TCP因为资源必须完整加载哪怕慢几百毫秒都能接受。从场景到协议再到机制这个链条贯通了答案自然脱口而出。7.3 动手实验的三个入门小项目如果只推荐三个动手项目我选下面这三个全部可以用普通电脑完成第一个用Python写一个最简单的UDP聊天室。核心代码不超过50行用socket库的socket(AF_INET, SOCK_DGRAM)就行。做完你就能真切感受到发送完不管的感觉你把消息发出去了对端收没收到你的代码完全不知道。第二个用Python写一个TCP回显服务器。先单线程版再用threading改成多线程版最后用async IO改成异步版。这个过程你能直观感受到TCP的字节流特性你可能一次recv到半个客户端消息也可能一次recv到好几个消息拼接在一起这在UDP里是绝对不可能发生的。第三个用Wireshark抓三次握手和四次挥手的包。先别急着记字段先把那4到7个包的源端口、目的端口、SYN/ACK/FIN标志和序列号变化抄在本子上再比对着画出完整的序列号变化图。这一个小实验做下来顶得上背十遍408教材。7.4 用iperf3和tcpdump构建自己的实验沙箱我真心建议你花一个下午配置一个推进式的小实验环境。准备两台虚拟机装好Linux系统然后在上面做这些实验iperf3 TCP打流调整窗口大小观察吞吐变化iperf3 UDP打流调整带宽参数观察丢包率变化tc人为注入丢包观察TCP快速重传和超时重传nc联合tcpdump抓包看UDP和TCP发送的报文差异这些实验需要的只是装好iperf3、tcpdump、tc这几个工具成本极低但带来的收益非常大。协议栈是一套工程实现理念再好你也得亲手看看它在真实内核里的行为才会真正信它。纸上得来终觉浅这句老话放到计算机网络领域比任何真理都真。8. 协议栈之外的隐约边界TCP/UDP与上层应用的一次对话8.1 不要让协议背锅先从应用层找问题带过几次team里的新人排障我发现一个通病只要网络有问题第一反应永远是把罪过推到TCP/UDP协议头上。但实际上绝大多数线上问题代码层要负主要责任。举个例子有个业务说TCP连接总是断抓包一看服务端回了RST。RST可不是TCP的随机故障它是应用中某段代码主动调用了错误处理逻辑我只知道一个典型的触发点是向一个已经关闭的socket写数据内核就会回一个RST。这时候你别说TCP协议不稳定你该去查业务逻辑里为什么还在往已关闭连接写东西。8.2 从socket编程看TCP与UDP的现实差异接触过socket编程的人应该体会过UDP的代码路径短得感人创建socket、bind、recvfrom、sendto完事。TCP则要listen、accept、recv、send中间还要应对半关闭、粘包、拆包、连接异常。这两种协议给开发者的心智负担完全不是一个量级。我提醒每个做网络编程的新人TCP粘包问题不是TCP协议的设计缺陷而是字节流模型带来的天然特性。你应用层要自己定义消息边界要么用固定长度要么用长度前缀要么用分隔符。把粘包怪到TCP头上就好比怪快递员把你的两封信塞进同一个箱子但你没有在信封上写收件人姓名。8.3 学会看内核的尺子一些立等可取的排查技巧最后分享几个我常用的快速排障命令全部来自内核提供的尺子非常简单但极其实用查看系统TCP连接状态分布ss -antp | awk {print $1} | sort | uniq -c查看指定端口的连接统计ss -antp | grep :8080 | wc -l查看UDP接收缓冲区是否溢出netstat -su | grep -i receive buffer如果看到UDP接收缓冲区错误数一直在涨而且你的UDP服务丢包严重第一件事就是调大系统UDP缓冲区sysctl -w net.core.rmem_max26214400 sysctl -w net.core.rmem_default26214400这套组合拳我在处理很多玄学丢包问题时都第一时间使用基本每次都能把问题定位到用户态消费太慢或者内核缓冲区太小这类实质原因上。不夸张地说熟练掌握这几个命令等于给自己配了一副看穿内核行为的显微镜。8.4 把知识缝进自己的话术里你应该形成的TCP/UDP小模型当你能够不看任何资料用不出五分钟的时间向别人完整地讲清楚下面这几件事就可以认为TCP和UDP这关真的过了UDP的报文头有哪4个字段为什么它不需要建立连接适合什么场景不适合什么场景TCP头部的主要字段各管什么序列号和确认号如何配合实现字节流的有序交付TCP三次握手为什么是三次四次挥手为什么是四次TIME_WAIT为什么存在TCP是如何通过超时重传、快速重传、滑动窗口、拥塞控制来保障可靠性的TCP和UDP各自的软肋在哪里什么场景必须绕过TCP的队头阻塞、什么场景必须容忍UDP的丢包我后来带实习生做过一次分享我把这套话术压缩成了一张A4纸叫TCP/UDP五分钟小模型。每次遇到跟网络协议有关的问题先套这个小模型再决定要不要深挖。这个方法帮团队省掉了大量无效的排查时间。我自己学计算机网络那阵子最遗憾的就是没有尽早建立一个协议好奇心的视角每遇到一个报错、一次延迟、一次重传都下意识地想这是TCP的哪个机制在起作用。等你开始下意识地用协议栈的语言去解释应用问题你就会发现网上那些网络不好就怪丢包的模糊论调渐渐骗不到你了。
返回列表