第三章 传输层 第四节 用户数据报协议UDP
课程信息
- 课程名称: 计算机网络原理
- 课程代码: 04741
- 授课教师: [教师姓名]
- 授课时间: [具体时间]
- 课时: 2学时
教学目标
知识目标
- 理解UDP协议的基本概念和特点
- 掌握UDP数据报的格式和字段含义
- 了解UDP与TCP的区别和联系
- 掌握UDP的应用场景和优缺点
能力目标
- 能够分析UDP数据报的格式
- 能够选择合适的传输层协议
- 能够进行简单的UDP编程
教学内容
一、UDP协议概述
1.1 什么是UDP
用户数据报协议(User Datagram Protocol,UDP) 是传输层的一个简单协议,提供无连接的、不可靠的数据传输服务。
1.2 UDP在OSI模型中的位置
┌─────────────────────────────────────┐
│ 应用层 (Application) │ ← HTTP, DNS, DHCP, SNMP
├─────────────────────────────────────┤
│ 表示层 (Presentation) │
├─────────────────────────────────────┤
│ 会话层 (Session) │
├─────────────────────────────────────┤
│ 传输层 (Transport) │ ← UDP, TCP
├─────────────────────────────────────┤
│ 网络层 (Network) │ ← IP
├─────────────────────────────────────┤
│ 数据链路层 (Data Link) │
├─────────────────────────────────────┤
│ 物理层 (Physical) │
└─────────────────────────────────────┘
1.3 UDP的特点详解
特点 | 详细说明 | 影响 |
---|
无连接 | 发送数据前不需要建立连接 | 减少延迟,提高效率 |
不可靠 | 不保证数据能够到达目的地 | 需要应用层处理可靠性 |
无状态 | 不维护连接状态信息 | 服务器可处理更多客户端 |
简单高效 | 协议开销小,传输效率高 | 适合实时应用 |
支持广播 | 可以同时向多个主机发送数据 | 适合网络发现和媒体分发 |
无流量控制 | 不控制发送速率 | 可能导致接收方缓冲区溢出 |
1.4 UDP与TCP的详细对比
特性 | UDP | TCP | 说明 |
---|
连接性 | 无连接 | 面向连接 | UDP直接发送,TCP需要三次握手 |
可靠性 | 不可靠 | 可靠 | UDP不保证送达,TCP保证送达 |
传输效率 | 高 | 低 | UDP开销小,TCP开销大 |
协议开销 | 8字节 | 20字节 | UDP头部更小 |
流量控制 | 无 | 有 | TCP有滑动窗口机制 |
拥塞控制 | 无 | 有 | TCP有慢启动、拥塞避免等 |
顺序保证 | 无 | 有 | TCP保证数据顺序 |
适用场景 | 实时应用 | 文件传输 | UDP适合对实时性要求高的应用 |
1.5 UDP的传输过程
发送方 网络 接收方
│ │ │
│ ──── UDP数据报 ────────→ │ │
│ │ ──── UDP数据报 ────────→ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
特点:
- 发送方直接发送数据,无需建立连接
- 数据可能丢失、重复或乱序
- 接收方可能收不到数据
二、UDP数据报格式
2.1 UDP数据报整体结构
┌─────────────────────────────────────────────────────────────┐
│ IP头部 (20字节) │
├─────────────────────────────────────────────────────────────┤
│ UDP头部 (8字节) │
├─────────────────────────────────────────────────────────────┤
│ UDP数据 (可变长度) │
└─────────────────────────────────────────────────────────────┘
2.2 UDP头部详细结构
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 源端口 | 目标端口 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 长度 | 校验和 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 数据 |
| (可变长度) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2.3 字段详细说明
字段 | 位数 | 说明 | 示例值 | 备注 |
---|
源端口 | 16位 | 发送方端口号 | 12345 | 0表示不需要回复 |
目标端口 | 16位 | 接收方端口号 | 53 | 标识目标应用 |
长度 | 16位 | UDP数据报总长度 | 28 | 最小值为8(仅头部) |
校验和 | 16位 | 错误检测码 | 0x1234 | 0表示不校验 |
数据 | 可变 | 应用层数据 | "Hello" | 最大65507字节 |
2.4 端口号详细分类
端口号范围分布图:
┌─────────────────────────────────────────────────────────────┐
│ 0 ──── 1023 ──── 49151 ──── 65535 │
│ │ │ │ │ │
│ │ │ │ │ │
│ 系统端口 注册端口 动态端口 │
│(Well-known) (Registered) (Dynamic) │
└─────────────────────────────────────────────────────────────┘
端口范围 | 类型 | 说明 | 示例 |
---|
0-1023 | 系统端口 | 系统保留,需要管理员权限 | 21(FTP), 22(SSH), 53(DNS), 80(HTTP) |
1024-49151 | 注册端口 | IANA分配,需要注册 | 1433(SQL Server), 3306(MySQL), 5432(PostgreSQL) |
49152-65535 | 动态端口 | 客户端临时使用 | 操作系统自动分配 |
2.5 常见UDP端口号
端口 | 协议 | 服务 | 说明 |
---|
53 | DNS | 域名解析 | 最常用的UDP服务 |
67/68 | DHCP | 动态主机配置 | 67服务器,68客户端 |
69 | TFTP | 简单文件传输 | 无认证的文件传输 |
123 | NTP | 网络时间协议 | 时间同步 |
161 | SNMP | 网络管理 | 设备监控 |
520 | RIP | 路由信息协议 | 内部网关协议 |
1900 | SSDP | 设备发现 | UPnP设备发现 |
2.6 UDP数据报长度限制
UDP数据报长度计算:
┌─────────────────────────────────────────────────────────────┐
│ IP头部: 20字节 (固定) │
├─────────────────────────────────────────────────────────────┤
│ UDP头部: 8字节 (固定) │
├─────────────────────────────────────────────────────────────┤
│ UDP数据: 最大65507字节 │
├─────────────────────────────────────────────────────────────┤
│ 总长度: 最大65535字节 (IP限制) │
└─────────────────────────────────────────────────────────────┘
计算公式:
最大UDP数据长度 = 65535 - 20(IP头部) - 8(UDP头部) = 65507字节
三、UDP的校验和机制
3.1 校验和计算过程
UDP校验和计算示意图:
┌─────────────────────────────────────────────────────────────┐
│ 伪头部 (12字节) │
│ ┌─────────────┬─────────────┬─────────┬─────────────────┐ │
│ │ 源IP地址 │ 目标IP地址 │ 零字段 │ UDP长度 │ │
│ │ (4字节) │ (4字节) │ (1字节) │ (2字节) │ │
│ └─────────────┴─────────────┴─────────┴─────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ UDP头部 (8字节) │
│ ┌─────────────┬─────────────┬─────────┬─────────────────┐ │
│ │ 源端口 │ 目标端口 │ 长度 │ 校验和(置0) │ │
│ │ (2字节) │ (2字节) │ (2字节) │ (2字节) │ │
│ └─────────────┴─────────────┴─────────┴─────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ UDP数据 (可变长度) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 应用层数据 │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
3.2 校验和计算步骤
步骤 | 操作 | 说明 |
---|
1 | 构造伪头部 | 包含源IP、目标IP、协议类型(17)、UDP长度 |
2 | 准备UDP头部 | 将校验和字段置0 |
3 | 添加数据 | 包含UDP数据部分 |
4 | 16位对齐 | 如果数据长度为奇数,末尾补0 |
5 | 16位求和 | 将所有16位字段相加 |
6 | 取反码 | 对结果取反码得到校验和 |
3.3 校验和计算示例
示例数据:
源IP: 192.168.1.1 (0xC0A80101)
目标IP: 192.168.1.2 (0xC0A80102)
协议: UDP (0x11)
UDP长度: 28 (0x001C)
源端口: 12345 (0x3039)
目标端口: 53 (0x0035)
UDP长度: 28 (0x001C)
校验和: 0 (0x0000)
数据: "Hello" (0x48656C6C6F)
计算过程:
伪头部: C0A80101 + C0A80102 + 0011 + 001C = 1952A
UDP头部: 3039 + 0035 + 001C + 0000 = 3088
数据: 4865 + 6C6C + 6F00 = 15BD1
总和: 1952A + 3088 + 15BD1 = 1A0C3
取反码: ~1A0C3 = E5F3C
校验和: 5F3C
3.4 校验和验证过程
接收方验证步骤:
┌─────────────────────────────────────────────────────────────┐
│ 1. 重新构造伪头部 │
│ 2. 使用接收到的UDP头部 │
│ 3. 使用接收到的UDP数据 │
│ 4. 按相同方法计算校验和 │
│ 5. 与接收到的校验和比较 │
│ 6. 如果相等则数据正确,否则有错误 │
└─────────────────────────────────────────────────────────────┘
3.5 校验和的作用和局限性
方面 | 说明 | 局限性 |
---|
错误检测 | 检测数据在传输过程中的错误 | 不能检测所有错误类型 |
完整性验证 | 确保数据未被篡改 | 不能防止恶意攻击 |
性能影响 | 增加计算开销 | 对实时应用有轻微影响 |
可选性 | 可以设置为0跳过校验 | 某些实现可能忽略校验和 |
3.6 校验和错误类型
UDP校验和能检测的错误:
┌─────────────────────────────────────────────────────────────┐
│ ✓ 单比特错误 │
│ ✓ 双比特错误 │
│ ✓ 奇数个比特错误 │
│ ✓ 数据顺序错误 │
│ ✗ 偶数个比特错误(某些情况) │
│ ✗ 数据完全替换(相同校验和) │
└─────────────────────────────────────────────────────────────┘
四、UDP的应用场景
4.1 适合UDP的应用分类
UDP应用场景分类图:
┌─────────────────────────────────────────────────────────────┐
│ 实时应用 │
│ ┌─────────────┬─────────────┬─────────────┬─────────────┐ │
│ │ 视频会议 │ 在线游戏 │ 直播流 │ 语音通话 │ │
│ │ (低延迟) │ (快速响应) │ (实时性) │ (实时性) │ │
│ └─────────────┴─────────────┴─────────────┴─────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 网络服务 │
│ ┌─────────────┬─────────────┬─────────────┬─────────────┐ │
│ │ DNS查询 │ DHCP配置 │ SNMP监控 │ NTP同步 │ │
│ │ (简单查询) │ (广播发现) │ (设备管理) │ (时间同步) │ │
│ └─────────────┴─────────────┴─────────────┴─────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 媒体传输 │
│ ┌─────────────┬─────────────┬─────────────┬─────────────┐ │
│ │ 音频流 │ 视频流 │ 广播流 │ 组播流 │ │
│ │ (容错性) │ (实时性) │ (一对多) │ (多播) │ │
│ └─────────────┴─────────────┴─────────────┴─────────────┘ │
└─────────────────────────────────────────────────────────────┘
4.2 具体应用案例分析
应用 | 协议 | 端口 | 为什么选择UDP | 特点 |
---|
DNS | DNS | 53 | 查询简单,需要快速响应 | 无状态,支持缓存 |
DHCP | DHCP | 67/68 | 需要广播,客户端无IP | 支持广播发现 |
NTP | NTP | 123 | 时间同步要求低延迟 | 简单的时间戳交换 |
SNMP | SNMP | 161 | 网络管理查询频繁 | 轻量级协议 |
TFTP | TFTP | 69 | 简单文件传输 | 无认证,快速传输 |
视频会议 | RTP | 动态 | 实时性要求高 | 可容忍少量丢包 |
在线游戏 | 自定义 | 动态 | 需要低延迟 | 快速响应玩家操作 |
4.3 不适合UDP的应用
不适合UDP的应用类型:
┌─────────────────────────────────────────────────────────────┐
│ 文件传输 │
│ ┌─────────────┬─────────────┬─────────────┬─────────────┐ │
│ │ FTP传输 │ HTTP下载 │ 邮件传输 │ 数据库同步 │ │
│ │ (完整性) │ (可靠性) │ (确认送达) │ (数据一致) │ │
│ └─────────────┴─────────────┴─────────────┴─────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 关键应用 │
│ ┌─────────────┬─────────────┬─────────────┬─────────────┐ │
│ │ 银行交易 │ 支付系统 │ 医疗数据 │ 法律文件 │ │
│ │ (准确性) │ (安全性) │ (完整性) │ (可靠性) │ │
│ └─────────────┴─────────────┴─────────────┴─────────────┘ │
└─────────────────────────────────────────────────────────────┘
4.4 UDP vs TCP 应用选择决策树
协议选择决策树:
┌─────────────────┐
│ 需要可靠性? │
└─────────┬───────┘
│
┌─────────┴───────┐
│ │
是 │ │ 否
│ │
┌───────────▼───────┐ │
│ 需要低延迟? │ │
└─────┬─────────────┘ │
│ │
┌─────┴─────┐ │
│ │ │
是│ │否 │
│ │ │
┌────▼────┐ ┌────▼────┐ │
│ UDP │ │ TCP │ │
│(实时) │ │(可靠) │ │
└─────────┘ └─────────┘ │
│
┌───────▼───────┐
│ 需要广播? │
└─────┬─────────┘
│
┌─────┴─────┐
│ │
是│ │否
│ │
┌─────▼─────┐ ┌───▼────┐
│ UDP │ │ TCP │
│ (广播) │ │(单播) │
└───────────┘ └────────┘
4.5 UDP应用性能特点
性能指标 | UDP表现 | 说明 |
---|
延迟 | 极低 | 无连接建立开销 |
吞吐量 | 高 | 无流量控制限制 |
CPU使用 | 低 | 协议处理简单 |
内存使用 | 低 | 无连接状态维护 |
可靠性 | 低 | 不保证数据送达 |
顺序性 | 无 | 不保证数据顺序 |
五、UDP的优缺点分析
5.1 UDP优点详细分析
UDP优点分析图:
┌─────────────────────────────────────────────────────────────┐
│ 性能优势 │
│ ┌─────────────┬─────────────┬─────────────┬─────────────┐ │
│ │ 低延迟 │ 高吞吐量 │ 低CPU使用 │ 低内存使用 │ │
│ │ (无连接) │ (无控制) │ (简单) │ (无状态) │ │
│ └─────────────┴─────────────┴─────────────┴─────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 功能优势 │
│ ┌─────────────┬─────────────┬─────────────┬─────────────┐ │
│ │ 支持广播 │ 支持组播 │ 无状态 │ 简单实现 │ │
│ │ (一对多) │ (多播) │ (无维护) │ (易开发) │ │
│ └─────────────┴─────────────┴─────────────┴─────────────┘ │
└─────────────────────────────────────────────────────────────┘
优点 | 详细说明 | 应用场景 | 性能影响 |
---|
简单高效 | 协议实现简单,传输效率高 | 实时应用 | 减少处理延迟 |
无连接开销 | 不需要建立和释放连接 | 频繁通信 | 提高响应速度 |
支持广播 | 可以同时向多个主机发送数据 | 网络发现 | 提高网络效率 |
实时性好 | 适合对实时性要求高的应用 | 音视频传输 | 保证用户体验 |
无状态 | 服务器不维护连接状态 | 高并发服务 | 支持更多客户端 |
灵活性强 | 应用层可以自定义可靠性机制 | 特殊应用 | 满足特定需求 |
5.2 UDP缺点详细分析
UDP缺点分析图:
┌─────────────────────────────────────────────────────────────┐
│ 可靠性问题 │
│ ┌─────────────┬─────────────┬─────────────┬─────────────┐ │
│ │ 数据丢失 │ 数据重复 │ 数据乱序 │ 数据损坏 │ │
│ │ (不保证) │ (可能) │ (可能) │ (可能) │ │
│ └─────────────┴─────────────┴─────────────┴─────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 控制问题 │
│ ┌─────────────┬─────────────┬─────────────┬─────────────┐ │
│ │ 无流量控制 │ 无拥塞控制 │ 无重传机制 │ 无确认机制 │ │
│ │ (可能溢出) │ (可能拥塞) │ (数据丢失) │ (无反馈) │ │
│ └─────────────┴─────────────┴─────────────┴─────────────┘ │
└─────────────────────────────────────────────────────────────┘
缺点 | 详细说明 | 潜在问题 | 解决方案 |
---|
不可靠 | 不保证数据到达 | 数据丢失 | 应用层重传机制 |
无流量控制 | 不控制发送速率 | 接收方缓冲区溢出 | 应用层流量控制 |
无拥塞控制 | 不检测网络拥塞 | 加剧网络拥塞 | 应用层拥塞控制 |
无顺序保证 | 数据可能乱序到达 | 数据顺序错乱 | 应用层排序机制 |
无连接管理 | 不维护连接状态 | 难以管理连接 | 应用层连接管理 |
安全性较低 | 缺乏内置安全机制 | 容易受到攻击 | 应用层安全机制 |
5.3 UDP vs TCP 优缺点对比表
特性 | UDP | TCP | 说明 |
---|
可靠性 | ❌ 不可靠 | ✅ 可靠 | TCP有确认、重传机制 |
顺序性 | ❌ 无顺序 | ✅ 有序 | TCP保证数据顺序 |
流量控制 | ❌ 无控制 | ✅ 有控制 | TCP有滑动窗口 |
拥塞控制 | ❌ 无控制 | ✅ 有控制 | TCP有拥塞避免 |
连接管理 | ❌ 无连接 | ✅ 有连接 | TCP维护连接状态 |
延迟 | ✅ 极低 | ❌ 较高 | UDP无连接建立开销 |
吞吐量 | ✅ 高 | ❌ 较低 | UDP无控制限制 |
CPU使用 | ✅ 低 | ❌ 较高 | UDP处理简单 |
内存使用 | ✅ 低 | ❌ 较高 | UDP无状态维护 |
广播支持 | ✅ 支持 | ❌ 不支持 | UDP支持一对多 |
实时性 | ✅ 优秀 | ❌ 一般 | UDP适合实时应用 |
5.4 UDP适用性评估
UDP适用性评估矩阵:
┌─────────────────────────────────────────────────────────────┐
│ 应用类型 │ 可靠性要求 │ 实时性要求 │ UDP适用性 │
├─────────────────────────────────────────────────────────────┤
│ 视频会议 │ 低 │ 高 │ ✅ 适合 │
│ 在线游戏 │ 低 │ 高 │ ✅ 适合 │
│ DNS查询 │ 中 │ 高 │ ✅ 适合 │
│ 文件传输 │ 高 │ 低 │ ❌ 不适合 │
│ 网页浏览 │ 高 │ 中 │ ❌ 不适合 │
│ 邮件传输 │ 高 │ 低 │ ❌ 不适合 │
│ 音频流 │ 低 │ 高 │ ✅ 适合 │
│ 银行交易 │ 高 │ 中 │ ❌ 不适合 │
└─────────────────────────────────────────────────────────────┘
六、UDP编程基础
6.1 UDP Socket编程流程
UDP编程流程图:
┌─────────────────────────────────────────────────────────────┐
│ 服务器端 │
│ ┌─────────────┬─────────────┬─────────────┬─────────────┐ │
│ │ 创建套接字 │ 绑定地址 │ 接收数据 │ 发送数据 │ │
│ │ socket() │ bind() │ recvfrom() │ sendto() │ │
│ └─────────────┴─────────────┴─────────────┴─────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
│ 数据交换
│
┌─────────────────────────────────────────────────────────────┐
│ 客户端 │
│ ┌─────────────┬─────────────┬─────────────┬─────────────┐ │
│ │ 创建套接字 │ 发送数据 │ 接收数据 │ 关闭套接字 │ │
│ │ socket() │ sendto() │ recvfrom() │ close() │ │
│ └─────────────┴─────────────┴─────────────┴─────────────┘ │
└─────────────────────────────────────────────────────────────┘
6.2 UDP服务器端代码示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
int sockfd;
struct sockaddr_in serv_addr, client_addr;
char buffer[BUFFER_SIZE];
socklen_t client_len = sizeof(client_addr);
// 1. 创建UDP套接字
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
// 2. 设置服务器地址
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(PORT);
// 3. 绑定地址
if (bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
perror("Bind failed");
exit(EXIT_FAILURE);
}
printf("UDP服务器启动,监听端口 %d\n", PORT);
// 4. 接收和发送数据
while (1) {
// 接收数据
int n = recvfrom(sockfd, buffer, BUFFER_SIZE, 0,
(struct sockaddr*)&client_addr, &client_len);
if (n < 0) {
perror("Receive failed");
continue;
}
buffer[n] = '\0';
printf("收到来自 %s:%d 的消息: %s\n",
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port),
buffer);
// 发送回复
char reply[] = "服务器已收到消息";
sendto(sockfd, reply, strlen(reply), 0,
(struct sockaddr*)&client_addr, client_len);
}
close(sockfd);
return 0;
}
6.3 UDP客户端代码示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 8080
#define BUFFER_SIZE 1024
int main() {
int sockfd;
struct sockaddr_in serv_addr;
char buffer[BUFFER_SIZE];
char message[] = "Hello, UDP Server!";
// 1. 创建UDP套接字
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
// 2. 设置服务器地址
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERVER_PORT);
serv_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
// 3. 发送数据
if (sendto(sockfd, message, strlen(message), 0,
(struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
perror("Send failed");
exit(EXIT_FAILURE);
}
printf("发送消息: %s\n", message);
// 4. 接收回复
int n = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, NULL, NULL);
if (n < 0) {
perror("Receive failed");
exit(EXIT_FAILURE);
}
buffer[n] = '\0';
printf("服务器回复: %s\n", buffer);
close(sockfd);
return 0;
}
6.4 UDP编程关键函数
函数 | 功能 | 参数说明 | 返回值 |
---|
socket() | 创建套接字 | AF_INET, SOCK_DGRAM, 0 | 套接字描述符 |
bind() | 绑定地址 | sockfd, sockaddr, addrlen | 0成功,-1失败 |
sendto() | 发送数据 | sockfd, buffer, len, flags, addr, addrlen | 发送字节数 |
recvfrom() | 接收数据 | sockfd, buffer, len, flags, addr, addrlen | 接收字节数 |
close() | 关闭套接字 | sockfd | 0成功,-1失败 |
6.5 UDP编程注意事项
UDP编程注意事项:
┌─────────────────────────────────────────────────────────────┐
│ 数据包大小 │
│ • 最大UDP数据包大小:65507字节 │
│ • 建议数据包大小:< 1500字节(避免分片) │
│ • 网络MTU通常为1500字节 │
├─────────────────────────────────────────────────────────────┤
│ 错误处理 │
│ • 检查sendto()和recvfrom()的返回值 │
│ • 处理网络错误和超时 │
│ • 实现重传机制(如需要) │
├─────────────────────────────────────────────────────────────┤
│ 地址管理 │
│ • 使用sockaddr_in结构体 │
│ • 注意字节序转换(htons, ntohs) │
│ • 正确处理客户端地址 │
└─────────────────────────────────────────────────────────────┘
6.6 常见UDP应用协议
协议 | 端口 | 用途 | 特点 |
---|
DNS | 53 | 域名解析 | 查询-响应模式,支持缓存 |
DHCP | 67/68 | 动态IP分配 | 广播发现,四步握手 |
SNMP | 161 | 网络管理 | 简单查询,支持陷阱 |
TFTP | 69 | 简单文件传输 | 无认证,块传输 |
NTP | 123 | 时间同步 | 时间戳交换,精度高 |
RIP | 520 | 路由协议 | 定期广播路由信息 |
SSDP | 1900 | 设备发现 | UPnP设备发现 |
6.7 UDP编程最佳实践
UDP编程最佳实践:
┌─────────────────────────────────────────────────────────────┐
│ 性能优化 │
│ • 使用适当的数据包大小 │
│ • 避免频繁的系统调用 │
│ • 使用非阻塞I/O(如需要) │
│ • 实现应用层缓冲 │
├─────────────────────────────────────────────────────────────┤
│ 可靠性保证 │
│ • 实现应用层确认机制 │
│ • 添加序列号检测重复 │
│ • 实现超时和重传 │
│ • 添加数据完整性检查 │
├─────────────────────────────────────────────────────────────┤
│ 安全考虑 │
│ • 验证数据来源 │
│ • 防止缓冲区溢出 │
│ • 实现访问控制 │
│ • 使用加密(如需要) │
└─────────────────────────────────────────────────────────────┘
课堂练习
练习1:UDP数据报分析
1.1 数据报结构分析
给定一个UDP数据报的十六进制表示:
IP头部: 45 00 00 1C 00 01 00 00 40 11 7C 9B 0A 00 00 01
UDP头部: 0A 00 00 02 08 00 08 00 00 08 00 00
数据: 48 65 6C 6C 6F
1.2 分析步骤
数据报分析流程图:
┌─────────────────────────────────────────────────────────────┐
│ 1. 识别IP头部 (前20字节) │
│ ┌─────────┬─────────┬─────────┬─────────┬─────────┐ │
│ │ 版本+长度│ 服务类型 │ 总长度 │ 标识符 │ 标志+偏移 │ │
│ │ 45 │ 00 │ 001C │ 0001 │ 0000 │ │
│ └─────────┴─────────┴─────────┴─────────┴─────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 2. 识别UDP头部 (8字节) │
│ ┌─────────┬─────────┬─────────┬─────────┐ │
│ │ 源端口 │ 目标端口 │ 长度 │ 校验和 │ │
│ │ 0A00 │ 0002 │ 0800 │ 0800 │ │
│ └─────────┴─────────┴─────────┴─────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 3. 识别数据部分 │
│ ┌─────────┬─────────┬─────────┐ │
│ │ 48 │ 65 │ 6C │ → "Hello" │
│ │ 6C │ 6F │ │ │
│ └─────────┴─────────┴─────────┘ │
└─────────────────────────────────────────────────────────────┘
1.3 问题解答
问题 | 答案 | 计算过程 |
---|
源端口号 | 2560 | 0x0A00 = 10×256 + 0 = 2560 |
目标端口号 | 2 | 0x0002 = 2 |
UDP数据长度 | 8 | 0x0800 = 8字节(仅头部) |
数据部分内容 | "Hello" | 0x48='H', 0x65='e', 0x6C='l', 0x6C='l', 0x6F='o' |
练习2:协议选择决策
2.1 应用场景分析表
应用 | 可靠性要求 | 实时性要求 | 数据量 | 推荐协议 | 理由 |
---|
在线视频播放 | 低 | 高 | 大 | UDP | 可容忍丢包,需要低延迟 |
文件下载 | 高 | 低 | 大 | TCP | 需要保证数据完整性 |
网络游戏 | 中 | 高 | 小 | UDP | 需要快速响应,可容忍少量丢包 |
网页浏览 | 高 | 中 | 中 | TCP | 需要保证页面完整性 |
视频会议 | 低 | 高 | 中 | UDP | 实时性要求高,可容忍丢包 |
银行交易 | 高 | 中 | 小 | TCP | 数据准确性至关重要 |
DNS查询 | 中 | 高 | 小 | UDP | 简单查询,需要快速响应 |
2.2 协议选择决策树练习
请为以下场景选择协议:
场景1: 在线直播平台
需求: 实时传输视频流,可容忍少量丢包
选择: UDP ✓
理由: 实时性要求高,丢包对用户体验影响较小
场景2: 电子邮件系统
需求: 确保邮件内容完整传输
选择: TCP ✓
理由: 数据完整性比传输速度更重要
场景3: 网络游戏
需求: 快速响应玩家操作,可容忍少量丢包
选择: UDP ✓
理由: 延迟比可靠性更重要
场景4: 文件备份系统
需求: 确保备份文件完整无误
选择: TCP ✓
理由: 数据完整性是首要考虑
场景5: 网络设备监控
需求: 定期查询设备状态,查询频繁
选择: UDP ✓
理由: 简单查询,需要高效传输
练习3:UDP编程实践
3.1 编程任务
任务:实现一个简单的UDP聊天程序
功能要求:
┌─────────────────────────────────────────────────────────────┐
│ 服务器端功能: │
│ • 监听指定端口 │
│ • 接收客户端消息 │
│ • 向所有连接的客户端广播消息 │
│ • 显示客户端连接信息 │
├─────────────────────────────────────────────────────────────┤
│ 客户端功能: │
│ • 连接到服务器 │
│ • 发送消息到服务器 │
│ • 接收服务器广播的消息 │
│ • 支持多客户端同时连接 │
└─────────────────────────────────────────────────────────────┘
3.2 编程提示
// 关键代码结构
struct client_info {
struct sockaddr_in addr;
char name[50];
int active;
};
// 服务器端主要逻辑
while (1) {
// 接收消息
n = recvfrom(sockfd, buffer, BUFFER_SIZE, 0,
(struct sockaddr*)&client_addr, &client_len);
// 处理消息
process_message(buffer, n, &client_addr);
// 广播给所有客户端
broadcast_message(buffer, n, &client_addr);
}
练习4:网络抓包分析
4.1 Wireshark抓包任务
任务:使用Wireshark分析UDP数据包
步骤:
1. 启动Wireshark,选择网络接口
2. 设置过滤器:udp
3. 运行DNS查询:nslookup www.baidu.com
4. 分析抓取到的UDP数据包
5. 填写分析报告
4.2 分析报告模板
字段 | 值 | 说明 |
---|
源IP地址 | | |
目标IP地址 | | |
源端口 | | |
目标端口 | | |
UDP长度 | | |
校验和 | | |
数据内容 | | |
协议类型 | | |
练习5:性能测试
5.1 UDP性能测试
测试目标:比较UDP和TCP的性能差异
测试方法:
┌─────────────────────────────────────────────────────────────┐
│ 1. 使用iperf工具测试带宽 │
│ iperf -s -u # 启动UDP服务器 │
│ iperf -c server_ip -u # 启动UDP客户端 │
├─────────────────────────────────────────────────────────────┤
│ 2. 使用ping测试延迟 │
│ ping -c 100 target_ip # 测试100次ping │
├─────────────────────────────────────────────────────────────┤
│ 3. 编写程序测试吞吐量 │
│ • 发送固定大小的数据包 │
│ • 统计发送和接收的数据量 │
│ • 计算传输速率 │
└─────────────────────────────────────────────────────────────┘
5.2 测试结果分析
测试项目 | UDP结果 | TCP结果 | 分析 |
---|
延迟 | | | |
吞吐量 | | | |
CPU使用率 | | | |
内存使用 | | | |
丢包率 | | | |
课后作业
理论题:
- 简述UDP协议的特点和适用场景
- 比较UDP和TCP的优缺点
- 解释UDP校验和的计算过程
实践题:
- 使用Wireshark抓取UDP数据包并分析
- 编写简单的UDP客户端/服务器程序
- 分析DNS查询过程中的UDP使用
思考题:
- 为什么DNS使用UDP而不是TCP?
- 如何在使用UDP的应用中实现可靠性?
参考资料
- 《计算机网络原理》李全龙编著
- 《计算机网络》谢希仁编著
- RFC 768 - User Datagram Protocol
- Wireshark网络分析实战
板书设计
UDP协议
├── 特点:无连接、不可靠、简单高效
├── 格式:源端口|目标端口|长度|校验和|数据
├── 应用:DNS、DHCP、实时应用
└── 编程:Socket API
讲义编写时间:[20250909]
下次课预告:TCP协议详解
评论0
暂时没有评论