元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
网络层
▶
IP协议
IP数据报格式
子网划分原理
CIDR无类寻址
IP分片与重组
IP选项字段
▶
ICMP协议
差错报文类型
Ping实现原理
Traceroute原理
▶
ARP协议
地址解析原理
ARP缓存表
代理ARP
▶
路由协议
RIP协议详解
OSPF协议原理
BGP协议机制
▶
IPv6协议
IPv6地址结构
IPv6报文格式
IPv6扩展头
IPv6过渡技术
▶
移动IP
移动IP原理
代理发现机制
注册与路由优化
▶
网络QoS
QoS服务模型
IntServ架构
DiffServ架构
MPLS技术
▶
NAT技术
NAT原理与类型
NAT穿透技术
NAT64与DNS64
▶
组播路由
组播基础
IGMP协议
PIM协议族
▶
网络安全
IPSec协议族
VPN技术详解
DDoS防护
▶
传输层
▶
TCP协议
三次握手机制
滑动窗口原理
拥塞控制算法
四次挥手过程
超时重传机制
TCP状态转换
快速重传机制
快速恢复算法
选择性确认SACK
时间戳选项
▶
UDP协议
数据报结构解析
实时传输优化
UDP校验和计算
UDP广播与多播
UDP性能调优
UDP可靠传输
▶
SCTP协议
SCTP协议概述
多宿主支持
多流传输
关联建立过程
心跳机制
▶
传输层安全
TLS协议详解
DTLS协议
密钥交换机制
证书验证
▶
应用层
▶
HTTP协议
请求响应模型
持久连接机制
HTTP消息格式
状态码详解
Cookie机制
HTTP缓存机制
HTTP认证机制
HTTPS详解
TLS/SSL协议
HTTP/1.0详解
HTTP/1.1详解
HTTP/2详解
HTTP/3详解
▶
DNS系统
域名解析过程
记录类型详解
递归与迭代查询
DNS缓存机制
▶
FTP协议
FTP工作原理
主动与被动模式
FTP命令详解
▶
SMTP协议
邮件传输流程
SMTP会话过程
邮件格式规范
▶
DHCP协议
DHCP工作原理
地址分配过程
DHCP中继代理
▶
SNMP协议
SNMP架构
MIB数据库
SNMP操作
SNMPv3安全机制
▶
WebSocket协议
WebSocket原理
握手升级机制
数据帧格式
心跳与连接维护
▶
QUIC协议
QUIC协议特性
0-RTT建连
多路复用
丢包恢复
▶
gRPC协议
gRPC基础
服务定义
通信模式
负载均衡
发布时间:
2025-03-25 08:35
↑
☰
# UDP校验和计算 UDP校验和是一种用于检测数据传输过程中是否发生错误的机制。虽然UDP是一个不可靠的传输协议,但它仍然提供了基本的错误检测功能。 ## 校验和的作用 1. 错误检测 - 检测传输过程中的比特错误 - 发现数据包是否被篡改 - 验证数据完整性 2. 可选特性 - UDP的校验和是可选的 - IPv4中可以禁用校验和 - IPv6中必须启用校验和 ## UDP首部格式 ```mermaid graph LR A[源端口] --> B[目的端口] B --> C[长度] C --> D[校验和] D --> E[数据] ``` ### 首部字段说明 1. 源端口(16位) 2. 目的端口(16位) 3. 长度(16位):UDP首部和数据的总长度 4. 校验和(16位):覆盖UDP首部和数据 ## 校验和计算过程 ### 1. 伪首部构造 ```c struct pseudo_header { uint32_t source_ip; // 源IP地址 uint32_t dest_ip; // 目的IP地址 uint8_t zero; // 固定为0 uint8_t protocol; // 协议号(17表示UDP) uint16_t udp_length; // UDP长度 }; ``` ### 2. 计算步骤 1. 准备数据 - 构造伪首部 - 将校验和字段置0 - 如果数据长度为奇数,补充一个字节的0 2. 16位字相加 ```c uint32_t sum = 0; uint16_t *ptr = (uint16_t *)buffer; // 对所有16位字进行求和 while (length > 1) { sum += *ptr++; length -= 2; } // 处理可能的单字节 if (length > 0) { sum += *(uint8_t *)ptr; } ``` 3. 进位处理 ```c // 处理高16位的进位 while (sum >> 16) { sum = (sum & 0xFFFF) + (sum >> 16); } ``` 4. 取反操作 ```c return (uint16_t)(~sum); ``` ## 实现示例 ### 1. 完整的校验和计算函数 ```c uint16_t udp_checksum(const void *buff, size_t len, uint32_t src_ip, uint32_t dst_ip) { const uint16_t *buf = (const uint16_t *)buff; uint32_t sum = 0; size_t length = len; // 1. 计算UDP数据的校验和 while (length > 1) { sum += *buf++; if (sum & 0x80000000) sum = (sum & 0xFFFF) + (sum >> 16); length -= 2; } // 2. 如果长度为奇数,处理最后一个字节 if (length & 1) { sum += *((uint8_t *)buf); } // 3. 添加伪首部的校验和 sum += (src_ip >> 16) & 0xFFFF; sum += (src_ip) & 0xFFFF; sum += (dst_ip >> 16) & 0xFFFF; sum += (dst_ip) & 0xFFFF; sum += htons(17); // UDP协议号 sum += htons(len); // UDP长度 // 4. 处理进位 while (sum >> 16) { sum = (sum & 0xFFFF) + (sum >> 16); } // 5. 取反 return (uint16_t)(~sum); } ``` ### 2. 使用示例 ```c // UDP数据包结构 struct udp_packet { struct udp_header header; char data[1500]; }; // 发送前计算校验和 void send_udp_packet(struct udp_packet *packet, size_t length) { // 1. 清零校验和字段 packet->header.checksum = 0; // 2. 计算校验和 packet->header.checksum = udp_checksum( packet, length, source_ip, dest_ip ); // 3. 发送数据包 send_packet(packet, length); } ``` ## 校验和验证 ### 1. 接收方处理 ```c bool verify_udp_checksum(const struct udp_packet *packet, size_t length, uint32_t src_ip, uint32_t dst_ip) { uint16_t received_checksum = packet->header.checksum; // 1. 计算校验和 uint16_t calculated_checksum = udp_checksum( packet, length, src_ip, dst_ip ); // 2. 比较校验和 return received_checksum == calculated_checksum; } ``` ### 2. 错误处理 ```c void handle_udp_packet(const struct udp_packet *packet, size_t length) { if (!verify_udp_checksum(packet, length, src_ip, dst_ip)) { // 校验和错误,丢弃数据包 log_error("UDP checksum verification failed"); return; } // 处理数据包 process_udp_data(packet->data); } ``` ## 性能优化 ### 1. 硬件卸载 现代网卡通常支持校验和卸载: - 发送时自动计算校验和 - 接收时自动验证校验和 - 减少CPU负载 ### 2. 软件优化 1. 使用查表法加速计算 ```c // 预计算的16位和表 static const uint16_t csum_table[256]; // 使用查表加速计算 sum += csum_table[byte]; ``` 2. SIMD指令集优化 - 使用SSE/AVX指令 - 并行处理多个16位字 - 提高计算速度 ## 调试技巧 ### 1. 使用tcpdump分析 ```bash # 抓取UDP数据包并显示校验和 tcpdump -i any -vv 'udp' ``` ### 2. 常见问题 1. 校验和始终为0 - 检查是否禁用了校验和 - 验证伪首部构造是否正确 - 确认字节序处理正确 2. 校验和不匹配 - 检查IP地址是否正确 - 验证长度计算是否准确 - 确认补零处理正确 ## 总结 UDP校验和虽然是一个简单的错误检测机制,但它提供了: 1. 基本的数据完整性保证 2. 错误检测能力 3. 防止数据包被篡改 在实际应用中,建议: 1. IPv6环境必须启用校验和 2. 合理使用硬件卸载功能 3. 实现正确的错误处理 4. 注意性能优化