Appearance
UDP(User Datagram Protocol)协议
用户数据报协议,简单的面向数据报的通信协议,位于
OSI
模型的传输层
UDP 只提供数据的不可靠传递,在 IP 数据报的头部仅仅加入了复用和数据校验字段
UDP 不需要执行错误检查和纠正,避免协议栈中此类处理的开销
对时间有较高要求的应用程序通常使用 UDP,丢失数据包比等待重传导致的延迟更可取
应用场景
- DNS
- DHCP 动态 IP 分配地址
- SNMP 简单网络管理协议
- RIP 路由信息协议
- NTP 网络时间协议
UDP 数据包结构
- UDP 伪首部(总长度 12)
- 32 位源 IP 地址
- 32 位目的 IP 地址
- 8 位 0
- 8 位协议 17 0x11
- 16 为 UDP 长度
- UDP 首部(总长度 8)
- 16 位源端口号
- 16 位目的端口号
- 16 位 UDP 长度
- 16 位校验和 checksump
- 数据
- 二进制数据
- 填充字节 0x00
checksum 计算
- checksum 中有两个长度值,具体为:
(数据长度 + 报头长度8)* 2
php
<?php
$udpHex = <<<HEX
0a 00 02 19 // src
0a 00 0d be // dest
00 11 // protocol
00 0c // udp length
d3 f7 // source port
27 07 // dest port
00 0c // length
00 00 // checksum rest
77 6f 72 64 // data
HEX;
$udpHex = <<<HEX
0a 00 02 19 // src
0a 00 0d be // dest
00 11 // protocol
00 0d // udp length
d3 f7 // source port
27 07 // dest port
00 0d // length
00 00 // checksum rest
68 65 6c 6c 6f // data
HEX;
// length = ( data length = 8 ) * 2
$checkSum = 0x9d2c;
$udpHex = preg_replace('#\s+//.*+#', '', $udpHex);
$udpHex = array_values(array_filter(preg_split('#\s|\n#', $udpHex)));
$buffer = [];
foreach ($udpHex as $idx => $hex) {
if ($idx % 2 == 1) {
continue;
}
if (isset($udpHex[$idx + 1])) {
$buffer[] = (sprintf('0x%s%s' , $hex, $udpHex[$idx + 1]));
} else {
$buffer[] = (sprintf('0x%s00', ($hex)));
}
}
function checkSum(array $buffer)
{
$sum = 0;
foreach ($buffer as $idx => $buf) {
$sum += hexdec($buf);
if ($sum >> 16 > 0) {
$sum = ($sum >> 16) + ($sum & 0xffff);
}
}
return '0x' . dechex((~$sum) & 0xffff ) ;
}
var_dump(checkSum($buffer));