新闻详情

新闻详情

首页 / 资讯中心 / 详情

UDP校验和详解:二进制反码求和、计算实例与Wireshark排查

发布时间:2026/9/30 11:37:11来源:尧图网络
UDP校验和详解:二进制反码求和、计算实例与Wireshark排查
1. 二进制反码16位世界里的“镜像相加”1.1 反码是什么为什么网络协议选中它最近被同事拉去排查一个基于UDP的自研协议“偶发丢包”抓包软件里每一帧报文看起来都正常可对端就是会漏数据。排查到一半我展开一帧UDP报文看到Checksum那一栏时突然意识到很多人对UDP的印象还停留在“无连接、不可靠、速度快”却忽略了首部里那2字节校验和字段。这个字段背后正是标题里说的“二进制反码检验”——协议文档里通常写成校验和Checksum中文教材叫“二进制反码运算求校验和”其实是一回事。互联网里IP、UDP、TCP、ICMP四大家族都在用同一套二进制反码求和做校验搞懂它等于一口气把整个协议栈的检验逻辑都打通了。二进制反码的定义非常简单把一个二进制数的每一位都取反0变1、1变0得到的就是反码英文叫Ones Complement。8位的0x5A0101 1010取反后是0xA51010 0101这很好理解。但反码和现代CPU普遍使用的补码有一个明显的差别补码体系里0只有一种表示反码体系里0有两种表示——0x00和0xFF都代表0。细想一下会觉得这有点别扭可网络协议栈偏偏就是从这“别扭”里捞到了好处。对两个反码数做加法规则比普通二进制加法多一步先按普通二进制逐位相加如果最高位16位字长就是第17位产生了进位这个进位不能丢掉必须回卷加到最低位。英文资料把这步叫end-around carry。为什么要多此一举因为在反码体系里最高位的进位本质上代表两个负数相加的结果直接丢弃进位会破坏反码加减法的对称性。回卷之后普通加法丢掉的那“1”被重新塞回结果里任何由进位引起的变化都会在最终结果上留下痕迹而这恰恰是后面UDP校验能工作的关键。1.2 三个理由轻量、对称、好判定校验和的选择很多CRC、哈希、奇偶校验都有各自的强项可整个互联网协议栈最终统一选了16位二进制反码求和我认为主要是三个原因。第一是算得快。反码求和只需要做一遍16位字的加法不需要查表、不需要多项式运算、不需要移位寄存器。早期网络设备的CPU非常弱包转发路径上每一项额外的计算都是性能负担而反码加法一包几微秒就能跑完。第二是硬件友好。正常的补码加法遇到最高位溢出直接丢掉进位反码加法要把进位输出再次接到最低位这个“环回”在电路上只要一根线就能实现。很多老网卡和路由器转发芯片就用这么简单的结构完成了整包校验可靠性高、门电路少。第三是接收端判定极其优雅。发送端把数据求和后取反得到校验和接收端则把校验和当作普通数据再加进同一批16位字里。由于“任何数加自己的反码都等于全1”接收端只需要检查最终结果是否为0xFFFF即可一次比较就能判定整包对错。这在几十年前CPU没有乘除法指令的年代是实实在在的省钱路子。当然反码求和属于“轻校验”它不追求像CRC那样检测所有常见错误模式只求用最少计算抓住大多数差错。这一取舍在UDP这种轻量协议里尤其合理——每台主机每秒钟可能处理成千上万个数据报校验逻辑必须廉价到可以被忽略。1.3 一算就懂的例证0xFFFF加0x0001光说规则不如算一个数。16位字长下0xFFFF取反是0x0000两者相加0xFFFF 0x0000 0xFFFF没进位。但如果算0xFFFF 0x0001呢普通二进制加法的结果是1 0000 0000 0000 0000第17位出现了一个1。按反码规则把这个进位回卷到最低位得到0x0000 0x0001 0x0001。别小看这个结果在反码算术里-00xFFFF加上1确实应该等于1回卷修正了普通加法丢弃进位导致的偏差。这个简单的例子背后藏着一个规律反码求和不放过最高位的溢出它把溢出的信息重新揉进低位继续算。后续UDP校验把几十个16位字一路加下来任何一次溢出都会影响最终和而最终和又决定了校验和于是哪怕只有一个bit出错绝大多数情况下最终结果都不会等于0xFFFF。2. UDP校验和的范围伪首部才是隐藏主角2.1 校验和覆盖三块伪首部、UDP首部、数据很多初学者以为UDP校验和只是把“UDP头数据”过一遍实际上UDP校验和计算还有一个前置部分叫伪首部Pseudo Header。伪首部不属于UDP报文它不会被发送到线路上但必须参与校验。IPv4下的伪首部一共12字节结构如下字段内容长度源IP地址取自IPv4报文头4字节目的IP地址取自IPv4报文头4字节0填充固定为全01字节协议号170x11代表UDP1字节UDP长度UDP首部数据的字节数2字节把IP层的关键地址拿来放进传输层校验范围这件事的意义在转发错误时才会显现。假设一台路由器的路由表配错了把一个本该发往主机A的UDP数据报转给了主机B主机B的IP层虽然会接收到这个包但重建出来的伪首部里目的IP一定和真正发送方填的不一致于是UDP校验失败数据报被丢弃。没有伪首部UDP只能验证“自己的首部和数据没坏”验证不了“这个包投递给的机器对不对”。2.2 发送端四步撑起整个计算无论是CPU里跑软件还是网卡里跑硬件发送端计算UDP校验和都逃不开四步。第一步组装伪首部。这一步需要的源IP、目的IP、协议号和UDP长度在IP层封装时都是确定的。第二步把伪首部、UDP首部、UDP数据依次看成一张16位整数列表。伪首部12字节正好是6个16位字UDP首部8字节是4个16位字剩下数据部分按每2字节一个16位字切分。如果数据总字节数是奇数就在末尾补一个全0字节参与计算但补的这个字节不发送接收端自然也会照样补上。第三步对这张列表里的所有16位整数做二进制反码求和。这里的求和就是第一章说的带回卷进位的加法从头到尾一个数一个数累加。第四步把求和结果的每一位取反得到的就是校验和填入UDP首部的校验和字段。我见过不少实现把顺序写反先取反再累加或者漏掉回卷进位导致计算结果和标准实现对不上。调试时最好的参照就是Wireshark对同一帧报文显示的正常校验和能多一个交叉验证的锚点。2.3 伪首部不传输接收端怎么重建伪首部既然不随报文发送接收端怎么保证两端用的是同一个伪首部答案是从IP首部重新提取。UDP层的数据报向上递交时内核里IP层已经把源IP、目的IP、总长度等信息解析出来UDP校验逻辑只需要照单抄录重建一个和发送端完全相同顺序的伪首部再走一遍相同的算法。顺带解决一个总有人问的疑惑TCP校验和是不是也这样TCP的校验算法和UDP几乎一致只是伪首部里的“UDP长度”换成“TCP长度”协议号从17换成6。把UDP这套搞明白TCP的校验和阅读和理解基本无障碍。所谓“二进制反码检验”本来就是整个TCP/IP协议栈通用的基本功。3. 接收端如何检验一份可跟着算的完整账本3.1 “全1”判定与0x0000的保留接收端的检验比发送端更聪明它不重新计算一个校验和再和收到的校验和做比较而是把收到的校验和也当作一个16位字直接加入整张列表的反码求和。发送端把原始和S取反得到~S接收端这轮计算实际是S ~S而在反码算术里任何16位数和它自己的反码相加结果恒等于0xFFFF。所以UDP接收端只看一个数字整张列表的反码求和结果是不是全1。是通过不是丢弃。这里有个容易被忽略的特例如果发送端算出来的校验和恰好是0x0000它不会把0填进报文而是用0xFFFF替代。原因在IPv4的UDP规范里写得很清楚校验和字段为全0表示“发送端根本没有生成校验和”接收端看到0就直接跳过校验。翻译成人话0x0000这组编码被留作“免检”信号了而真正计算结果是0的那点概率就交给0xFFFF来代表。反码体系里本来就有两个零这里把“正零”和“负零”都用得恰到好处。3.2 完整算例从源地址到数据逐字求和纸上谈兵到此为止我手算一个完整例子你们可以拿纸笔跟一遍。设一帧IPv4 UDP报文源IP192.168.1.10即0xC0A8 0x010A目的IP192.168.1.20即0xC0A8 0x0114UDP源端口0x1234目的端口0x5678UDP数据4字节0x1122、0x3344于是UDP长度8字节首部4字节数据0x000C把伪首部、UDP首部、数据切成16位字一共11个字序号16位字含义10xC0A8源IP前2字节20x010A源IP后2字节30xC0A8目的IP前2字节40x0114目的IP后2字节50x0011填充0协议1760x000C伪首部中的UDP长度70x1234UDP源端口80x5678UDP目的端口90x000CUDP首部中的长度100x1122数据前2字节110x3344数据后2字节逐字做反码求和0xC0A8 0x010A 0xC1B20xC1B2 0xC0A8 0x1825A进位回卷后得0x825B0x825B 0x0114 0x836F0x836F 0x0011 0x83800x8380 0x000C 0x838C0x838C 0x1234 0x95C00x95C0 0x5678 0xEC380xEC38 0x000C 0xEC440xEC44 0x1122 0xFD660xFD66 0x3344 0x130AA进位回卷后得0x30AB原始和是0x30AB每一位取反得到校验和0xCF54填充进报文。接收端把这11个字加上校验和0xCF54再来一次反码求和最后得到0xFFFF检验通过。如果想验证自己写的计算程序对不对拿这个例子跑一遍是最快的办法。3.3 失败之后静默丢弃没有第二句话如果接收端算出来的最终和不是0xFFFFUDP层会直接丢弃这个数据报不通知应用层、不要求重传、不会给发送端回任何错误消息。TCP遇到类似问题有序列号和重传机制兜底UDP没有它甚至连“我丢了一个坏包”都不会说。这个特性对开发者的首要启示是16位校验和只能证明“传输过程中没有发生能被该算法检出的bit差错”不能证明“应用层拿到的一定是正确的包”。比如两个16位字整体互换位置由于加法交换律反码求和结果不变校验依然通过再比如校验和本身恰好产生了碰撞错误也会被漏检。所以凡是承载业务数据的UDP协议应用层还是应该根据重要程度补一层自己的校验最简单的是在载荷尾部带CRC32或者采样更重的摘要算法。别把UDP那2字节校验当防弹衣。4. 实验验证用iperf3、Wireshark和Linux计数器把它看穿4.1 先用iperf3把UDP流量打起来理论是一回事看得到真实校验行为是另一回事。我习惯用iperf3制造可控的UDP流量。先在一台机器上启动服务端iperf3 -s在另一台机器上以UDP模式打流持续10秒带宽50MbpsUDP负载1400字节iperf3 -u -c 192.168.1.20 -b 50M -l 1400 -t 10这里把负载压到1400字节是有意的加上8字节UDP首部和20字节IPv4首部整包约1428字节不会超过常见的1500字节MTU因此不会触发IP分片。后面我会专门讲分片对校验和的影响先让流量在最朴素的状态下跑起来。打流的同时在任一端用tcpdump抓包保存成文件tcpdump -i eth0 -s 0 -w udp_checksum.pcap udp port 5201如果打的不是默认端口记得把端口号换成实际值。抓完用Wireshark打开重点看每帧报文的UDP部分。4.2 Wireshark的三种校验和状态Wireshark里UDP Checksum字段常见三种状态很多人没搞明白区别。第一种是“unverified”或根本没有状态。因为Wireshark默认并不验证UDP校验和只在报文里展示Checksum的原始值。想看验证结果需要在 Preferences → Protocols → UDP 里勾选Validate the UDP checksum if possible开启后Wireshark才会真正计算并标记。第二种是“valid”即Wireshark按当前抓到的头部字段和载荷计算一遍校验和正好吻合。第三种是“invalid”即计算出来的值和报文里填的不一致这时要警惕有可能是真实传输错误也有可能是抓包机制造成的假象具体见下一节。另外某些IPv4 UDP包校验和字段本身是0x0000Wireshark会显示为“not present”之类的状态表示发送端没生成校验和。这个状态在抓包里是合规的但它意味着这条链路上UDP没有任何差错检测能力。4.3 Checksum Offload制造的第一桩假案新手最容易在这里翻车在自己机器上跑iperf3客户端同时在同机抓包会看到一大片UDP包校验和显示invalid。我最初也以为网络坏了后来才发现这是网卡硬件校验卸载Checksum Offload的正常表现。现代网卡为了减少CPU开销允许驱动在发数据时先把校验和字段留空数据到达网卡后由硬件把校验和填好再发到线上。抓包工具在软件层面截获的报文是校验和还没来得及填写的版本于是Wireshark计算出来当然对不上。这不代表业务出错只说明你抓的时机比硬件填写早了一步。处理办法有两种一不要在本机抓“发送方向”的包去对端或交换机镜像口抓那里的包已经带好硬件填写的校验和二临时关闭发送卸载让驱动自己填充ethtool -K eth0 tx off排查完可以重新打开ethtool -K eth0 tx on踩过一次这个坑之后我写排查记录时都会先把有无offload写进环境说明不知道这个背景的人看到满屏invalid很容易误判成链路质量问题。5. 绕不开的工程坑卸载、零校验和、分片重组5.1 用netstat -su验证“校验失败被丢弃”接收方向如果真的有校验错误最直观的观测点是内核统计。Linux下执行netstat -suUDP段里有个字段叫InCsumErrors不同发行版名称可能略有差异常见的有InChecksumErrors专门记录IP重组后因为校验和失败被丢弃的UDP数据报数量。我建议排查时把这个字段当“晴雨表”先记一个基线值再复现问题如果InCsumErrors在增长说明确实有包在UDP校验环节被丢弃优先怀疑物理链路质量、中间设备损坏、MTU导致的分片丢失等问题如果这个字段纹丝不动而应用依然异常就该往上层协议逻辑、接收缓冲区、端口冲突方向查。为了验证这个计数器真的会增长可以用Scapy故意构造一帧校验和错误的UDP包发到本机回环或局域网对端from scapy.all import * ip IP(src192.168.1.10, dst127.0.0.1) udp UDP(sport1111, dport9999) udp.chksum 0x1234 send(ip/udp, verboseFalse)Scapy默认会自动计算UDP校验和但要测试校验失败手动赋一个明显错误的值即可。发送后在接收端再次执行netstat -su会看到InCsumErrors增加了1。这个实验能帮你建立“校验失败等于静默丢弃”的肌肉记忆也会让你对协议行为的直觉更准确。5.2 IPv4的零校验和与IPv6的强制校验IPv4给UDP留了一个“免检”后门校验和字段为0表示没有计算校验和接收端不得做校验。为什么会有这个后门早期一些嵌入式系统、工业控制设备、组播应用为了省CPU故意不填校验和在可信的局域网里这还能将就一旦数据要跨公网或者穿过质量较差的链路没有校验和等于睁着眼睛让损坏的数据进门。我处理过的工业组播场景里就见过不少这类包比如某些PLC或老旧设备的UDP组播抓包一看校验和字段就是0。这时候要先判断是协议本身规定还是设备实现偷懒不要一看到全0就当成故障。但如果你在自研产品里对可靠性有要求尽量不要使用全0校验和尤其不能沿用“组播嘛不需要校验”的老观念。IPv6则直接关掉了这个后门IPv6要求所有UDP数据报必须计算校验和并且校验和字段不允许为0收到校验和为0的IPv6 UDP包要当作非法包丢弃。所以到了IPv6时代二进制反码检验不再是可选项而是UDP的硬性义务。5.3 分片之后UDP校验和去哪了最后一个容易和校验和混淆的坑是分片。当UDP负载超过路径MTU时IP层会把一个数据报切分成多个IP分片。很多人以为每个分片都有自己的UDP校验和其实不是。UDP校验和是在分片之前对整个UDP报文伪首部UDP首部完整数据一次性计算完成的。IP分片只是在原始字节流上按偏移裁剪第一个分片里才有UDP首部和校验和后续分片只有IP首部加一段载荷不再包含任何UDP字段。接收端必须等所有分片到齐、IP层重组出完整UDP报文后才执行UDP校验和验证。也就是说如果中途丢了任何一个分片IP层重组失败整包被放弃UDP校验和根本来不及出场。这个机制给排查带来一个很实际的顺序建议遇到UDP大包丢包先看IP层的分片标志Flags和偏移Fragment offset看是否出现大量“只有前片没有后片”的情况可能有分片丢失或重组缓冲区不足确定分片正常再往下看UDP校验和。把层次分开排错速度会快很多。我在实际项目里不止一次遇到同事在应用层反复查CRC最后发现丢的是IP分片UDP校验和连上场的机会都没有整个排查方向从一开始就偏了。写到这里按我的习惯做个收尾。其实也不是总结就是一个每次排查UDP问题都会做的动作不管问题表象多奇怪永远先在接收端看一眼netstat -su里的InCsumErrors和收包总数把“校验失败”和“收包数量异常”先量化没有异常再上抓包工具。二进制反码检验这套机制在UDP里既廉价又被大量忽略很多时候它只是安静地丢包却能把物理链路问题和应用逻辑问题分隔开。把校验这一层先确认干净后面的排查才有意义。希望这篇文章能把“二进制反码检验”从课本上的概念变成你手里一个顺手好用的排错工具。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

用Python和Tkinter打造桌面天气应用:从API接入到PyInstaller打包全攻略 2026/9/30 12:27:34

用Python和Tkinter打造桌面天气应用:从API接入到PyInstaller打包全攻略

说实话,我手机上是有天气App的,但每次想看一眼今天要不要带伞,都要解锁、打开App、等广告、找温度在哪一栏……到了办公室更是懒得掏手机,直接打开浏览器又觉得为这点事开个标签页很傻。后来我花了一个下午,用Python写…

阅读更多 →
文献综述不再是文献堆砌|Paperxie 文献综述模块实操全解 2026/9/30 12:27:34

文献综述不再是文献堆砌|Paperxie 文献综述模块实操全解

前言 文献综述是论文的根基,也是很多同学的一大难点。 不少同学写综述,只是简单摘抄多篇文献摘要,罗列作者观点,写成流水账,盲审专家一眼就能看出问题。 合格的文献综述,核心不是文献罗列,而是…

阅读更多 →
AI工程从零构建:可验证、可压测、可回滚的服务骨架 2026/9/30 12:27:33

AI工程从零构建:可验证、可压测、可回滚的服务骨架

1. 这不是“搭个LLM API”——AI工程从零开始的真实含义 很多人看到“AI Engineering from Scratch”第一反应是:不就是调个OpenAI接口、写个Flask后端、前端加个聊天框?我试过,也带过十几支团队做过类似项目,结果90%的交付物在上…

阅读更多 →
Qwen-Image-2.1人像提示词实战:生成、编辑与修复 2026/9/30 12:27:33

Qwen-Image-2.1人像提示词实战:生成、编辑与修复

Qwen-Image-2.1人像提示词大全:人像生成、发型表情编辑与老照片修复(附整合包下载)从Qwen-Image-2.0到2.1,我最直观的感受是:它终于把"人像"这件事做得像样了。年初我拿它跟几个主流开源模型在人像上做过一轮…

阅读更多 →
GEO如何让品牌进入AI答案?个人微信API接口如何承接AI搜索带来的用户需求 2026/9/30 12:27:32

GEO如何让品牌进入AI答案?个人微信API接口如何承接AI搜索带来的用户需求

GEO不是传统SEO的翻版。传统SEO优化搜索引擎排名——让网页排在结果前面。GEO优化AI答案——让品牌信息出现在AI搜索引擎的回答里。用户问AI"敏感肌用什么面膜好",AI回答里提到你的品牌,这就是GEO的效果。品牌进入AI答案后,用户带着…

阅读更多 →
SUMPRODUCT函数详解:条件求和、加权平均与常见错误 2026/9/30 12:27:26

SUMPRODUCT函数详解:条件求和、加权平均与常见错误

1. SUMPRODUCT到底是什么:先搞懂它的计算规则1.1 官方语法别背错,直接理解“对应相乘再相加”很多人第一次看到SUMPRODUCT这个函数名就懵了——SUMPRODUCT?Sum和Product的组合?对,它拆开就是“求和”加“乘积”&#x…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉