【Linux】UDP协议详解:无连接、不可靠但高效的传输协议

文章目录

UDP协议详解:无连接、不可靠但高效的传输协议

💬 开篇:前面我们学习了HTTP、HTTPS等应用层协议,这些协议都运行在传输层之上。传输层负责把数据从"本机某个进程"送到"对端某个进程"(靠端口号复用/分用)。传输层有两个主要协议:TCP和UDP。TCP复杂但可靠,UDP简单但高效。这一篇先从UDP讲起,理解UDP的设计哲学------放弃可靠性换取高效率。掌握UDP,你就理解了为什么有些应用选择UDP而不是TCP,比如视频直播、在线游戏、DNS查询。

👍 点赞、收藏与分享:这篇会把UDP的原理讲透,包括报文格式、特点、缓冲区机制、应用场景。如果对你有帮助,请点赞收藏!

🚀 循序渐进:从传输层的概念讲起,到端口号,到UDP报文格式,到UDP的特点,到缓冲区机制,到应用场景,一步步理解UDP为什么这样设计。


一、传输层的作用

1.1 网络分层回顾

还记得我们之前讲过的网络分层吗?

bash 复制代码
应用层:HTTP、HTTPS、FTP、SSH、DNS、SMTP...
传输层:TCP、UDP
网络层:IP
数据链路层:以太网、WiFi
物理层:光纤、电缆

传输层的位置:介于应用层和网络层之间。

传输层的职责

  • 应用层的数据如何传输到对方的应用层
  • 不关心数据怎么在网络上跑(那是网络层的事)
  • 只关心数据能否可靠地到达对方

1.2 传输层的核心概念:端口号

问题:一台主机上可能运行多个应用程序,比如:

  • 浏览器(HTTP)
  • 邮件客户端(SMTP)
  • SSH客户端
  • 游戏

如何区分这些应用程序的数据

答案:端口号(Port)。

端口号的作用:标识一个主机上进行通信的不同应用程序。

类比

bash 复制代码
IP地址 = 城市地址(找到哪个城市)
端口号 = 房间号(找到城市里的哪个房间)

1.3 五元组:唯一标识一条通信

在TCP/IP协议中,一条通信由五个要素唯一标识:

bash 复制代码
(源IP, 源端口, 目的IP, 目的端口, 协议号)

例子

bash 复制代码
(192.168.1.100, 54321, 8.8.8.8, 53, UDP)

这表示:

  • 从192.168.1.100的54321端口
  • 到8.8.8.8的53端口
  • 使用UDP协议

查看本机的通信五元组

bash 复制代码
netstat -n

输出示例:

bash 复制代码
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 192.168.1.100:54321     8.8.8.8:443            ESTABLISHED
udp        0      0 192.168.1.100:53214     8.8.8.8:53             

1.4 端口号的范围划分

端口号范围:0 - 65535(16位无符号整数)

分类

范围 名称 用途
0-1023 知名端口(Well-Known Port) 系统保留,常用服务
1024-65535 动态端口(Dynamic Port) 客户端程序、临时端口

常见知名端口

服务 端口 协议
SSH 22 TCP
Telnet 23 TCP
FTP 21 TCP
HTTP 80 TCP
HTTPS 443 TCP
DNS 53 UDP/TCP
SMTP 25 TCP
POP3 110 TCP
MySQL 3306 TCP
Redis 6379 TCP

查看系统的知名端口

bash 复制代码
cat /etc/services

重要:自己写程序时,要避开这些知名端口。

1.5 端口号的两个问题

问题1:一个进程能bind多个端口吗?

答案:可以。

例子

cpp 复制代码
// 一个服务器程序同时监听多个端口
TcpServer server1("0.0.0.0", 8080);  // 监听8080
TcpServer server2("0.0.0.0", 8081);  // 监听8081
TcpServer server3("0.0.0.0", 8082);  // 监听8082

实际应用

  • Nginx同时监听80和443端口
  • MySQL主从复制,主库监听3306,从库也监听3306
问题2:一个端口能被多个进程bind吗?

答案:不能(默认情况下)。

例子

bash 复制代码
# 进程A监听8080
./server 8080

# 进程B尝试监听8080
./server 8080
# 错误:Address already in use

例外:某些情况下可以通过 socket 选项实现端口重用。

SO_REUSEADDR 常用于"端口快速重启复用"(避免 TIME_WAIT 等导致的占用)

Linux 下如果要"多个进程同时监听同一端口并做负载分担",通常用 SO_REUSEPORT


二、UDP协议概述

2.1 UDP是什么

UDP(User Datagram Protocol):用户数据报协议。

设计哲学:简单、快速、高效。

代价:不可靠。

类比

bash 复制代码
TCP = 挂号信(可靠,但慢)
UDP = 明信片(快速,但可能丢失)

2.2 UDP报文格式

UDP报文结构

bash 复制代码
┌─────────────────────────────────────────┐
│         UDP首部(8字节)                 │
├─────────────────────────────────────────┤
│  源端口号(16位)  │  目的端口号(16位)  │
├─────────────────────────────────────────┤
│  长度(16位)      │  校验和(16位)      │
├─────────────────────────────────────────┤
│         UDP数据(可变长度)              │
└─────────────────────────────────────────┘

字段说明

  1. 源端口号(16位):发送方的端口
  2. 目的端口号(16位):接收方的端口
  3. 长度(16位):整个UDP报文的长度(首部+数据),最小8字节,最大65535字节
  4. 校验和(16位):用于差错检测(UDP不是 CRC,而是 16 位一补和),计算时还会包含 IP 的"伪首部",用于尽早发现报文在传输中被破坏或投递错误。
  5. 数据:应用层的数据

重要:UDP首部只有8字节,非常简洁。

2.3 UDP的特点

特点1:无连接

含义:不需要建立连接就可以直接发送数据。

对比TCP

bash 复制代码
TCP:
1. connect(建立连接)
2. send/recv(传输数据)
3. close(关闭连接)

UDP:
1. sendto(直接发送)

优点

  • 速度快(省去握手过程)
  • 开销小(不需要维护连接状态)

缺点

  • 无法确认对方是否存在
  • 无法确认对方是否收到
特点2:不可靠

含义:不保证数据一定能到达对方。

可能发生的情况

  • 数据丢失(网络拥塞、路由器故障)
  • 数据损坏(传输过程中出错)
  • 数据乱序(不同路径到达)

UDP的态度

bash 复制代码
"我尽力了,但不保证。"

对比TCP

bash 复制代码
TCP:
- 数据丢失 → 重传
- 数据损坏 → 丢弃并重传
- 数据乱序 → 重新排序

UDP:
- 数据丢失 → 不管
- 数据损坏 → 丢弃
- 数据乱序 → 不管

应用层的责任

bash 复制代码
如果应用层需要可靠性,就自己实现。
特点3:面向数据报

含义:UDP保留应用层数据的边界。

具体表现

  • 应用层发送多少数据,UDP就发送多少
  • 不会拆分数据
  • 不会合并数据

例子

cpp 复制代码
// 发送端
char data[100] = "hello";
sendto(sock, data, 100, 0, ...);  // 发送100字节

// 接收端
char buf[100];
recvfrom(sock, buf, 100, 0, ...);  // 接收100字节
// 必须一次接收100字节,不能分多次接收

UDP 保留报文边界:一次 recvfrom 只能读到一个完整的 UDP 报文。

如果接收缓冲区 buf 比报文小,报文会被截断,多出来的部分直接丢弃(不会像 TCP 那样下次还能继续读)。
对比TCP

bash 复制代码
TCP是面向字节流的,可以分多次读写。
UDP是面向数据报的,必须一次读写完整的报文。

重要:这是UDP和TCP最大的区别之一。


三、UDP缓冲区机制

3.1 UDP没有真正的发送缓冲区

TCP的发送缓冲区

bash 复制代码
应用层 → 发送缓冲区 → 网络层 → 网络

TCP会把数据先放在缓冲区,然后逐步发送。

UDP的发送过程

bash 复制代码
应用层 → 直接交给网络层 → 网络

UDP调用sendto后,数据直接交给内核的网络层,不经过缓冲区。

含义

  • sendto返回成功 ≠ 数据一定能到达对方
  • sendto返回成功只表示数据交给了网络层

3.2 UDP有接收缓冲区

接收缓冲区的作用

  • 存储从网络接收到的UDP报文
  • 应用层通过recvfrom从缓冲区读取

接收缓冲区的特点

  1. 不保证顺序
bash 复制代码
发送:报文1 → 报文2 → 报文3
接收缓冲区可能是:报文2 → 报文1 → 报文3
  1. 容量有限
bash 复制代码
如果缓冲区满了,新到达的报文会被丢弃。
  1. 报文边界清晰
bash 复制代码
每个报文都是独立的,不会混在一起。

3.3 UDP的全双工特性

全双工(Full Duplex):一个连接既可以读,也可以写。

UDP socket的特点

cpp 复制代码
// 同一个socket既可以发送,也可以接收
sendto(sock, ...);   // 发送
recvfrom(sock, ...); // 接收

对比TCP

bash 复制代码
TCP也是全双工的,但需要先建立连接。
UDP不需要连接,天生就是全双工的。

四、UDP的使用注意事项

4.1 UDP报文大小限制

UDP报文的最大长度:65535字节(16位长度字段)

实际限制

bash 复制代码
理论最大值:65535字节
UDP首部:8字节
IP首部:20字节
实际数据:65535 - 8 - 20 = 65507字节

但还有更严格的限制

MTU(Maximum Transmission Unit):最大传输单元。

bash 复制代码
以太网的MTU:1500字节
WiFi的MTU:1500字节

实际可传输的UDP数据

bash 复制代码
1500 - 20(IP首部) - 8(UDP首部) = 1472字节

超过MTU的处理

bash 复制代码
如果UDP报文超过MTU,IP层会进行分片。
分片后,如果任何一片丢失,整个报文就无法重组。

建议

bash 复制代码
UDP报文大小不要超过1472字节。
如果需要传输更大的数据,在应用层手动分包。

4.2 UDP的校验和

校验和的作用:检测报文是否损坏。

如果校验和出错

bash 复制代码
UDP直接丢弃该报文,不通知应用层。

应用层的感受

bash 复制代码
"咦,这个报文怎么没了?"

4.3 UDP的应用层协议设计

由于UDP的不可靠性,应用层需要自己处理

  1. 数据完整性
bash 复制代码
添加校验码或哈希值
  1. 数据顺序
bash 复制代码
添加序列号
  1. 数据可靠性
bash 复制代码
如果需要可靠性,自己实现重传机制
  1. 数据边界
bash 复制代码
由于UDP是面向数据报的,这个不用担心

五、基于UDP的应用层协议

5.1 为什么选择UDP

UDP的优势

  • 速度快(无连接开销)
  • 延迟低(直接发送)
  • 开销小(首部只有8字节)

适用场景

  • 实时性要求高
  • 对可靠性要求不高
  • 需要广播/多播

5.2 常见的UDP应用

DNS(Domain Name System)

功能:域名解析。

为什么用UDP

  • 查询通常很小(一个域名)
  • 响应也很小(一个IP地址)
  • 实时性要求高
  • 如果丢失,客户端会重新查询

例子

bash 复制代码
# DNS查询
nslookup www.google.com

# 使用UDP的53端口
DHCP(Dynamic Host Configuration Protocol)

功能:动态分配IP地址。

为什么用UDP

  • 客户端还没有IP地址,无法用TCP
  • 需要广播(UDP支持广播)
NTP(Network Time Protocol)

功能:网络时间同步。

为什么用UDP

  • 实时性要求高
  • 数据量小
视频直播、在线游戏

为什么用UDP

  • 实时性要求极高
  • 丢失几帧不影响用户体验
  • 不需要完全可靠

例子

bash 复制代码
直播:丢失一帧视频,用户看不出来
游戏:丢失一个位置更新,下一帧会纠正
TFTP(Trivial File Transfer Protocol)

功能:简单文件传输。

为什么用UDP

  • 简单(不需要TCP的复杂机制)
  • 用于无盘设备启动

5.3 自定义UDP应用层协议

当你写UDP程序时

cpp 复制代码
// 定义自己的协议
struct Request {
    uint32_t id;           // 请求ID
    uint32_t seq;          // 序列号
    char data[1024];       // 数据
};

struct Response {
    uint32_t id;           // 响应ID
    uint32_t seq;          // 序列号
    uint32_t status;       // 状态码
    char data[1024];       // 数据
};

// 发送请求
Request req;
req.id = 1;
req.seq = 1;
strcpy(req.data, "hello");
sendto(sock, &req, sizeof(req), 0, ...);

// 接收响应
Response resp;
recvfrom(sock, &resp, sizeof(resp), 0, ...);

六、UDP vs TCP快速对比

6.1 对比表

特性 UDP TCP
连接 无连接 面向连接
可靠性 不可靠 可靠
顺序 不保证 保证顺序
速度
首部大小 8字节 20-60字节
数据格式 数据报 字节流
流量控制
拥塞控制
广播/多播 支持 不支持

6.2 选择标准

选择UDP

  • 实时性要求高(视频、游戏、VoIP)
  • 对可靠性要求不高
  • 需要广播/多播
  • 数据量小

选择TCP

  • 需要可靠传输(文件传输、邮件)
  • 需要有序到达
  • 需要流量控制
  • 需要连接管理

七、本篇总结

7.1 核心要点

传输层的作用

  • 负责数据从发送端传输到接收端
  • 通过端口号区分不同的应用程序
  • 五元组唯一标识一条通信

端口号

  • 0-1023:知名端口(系统保留)
  • 1024-65535:动态端口(客户端使用)

UDP的特点

  • 无连接:直接发送,不需要握手
  • 不可靠:不保证到达、顺序、完整性
  • 面向数据报:保留应用层数据边界

UDP缓冲区

  • 无真正的发送缓冲区(直接交给网络层)
  • 有接收缓冲区(存储接收的报文)
  • 接收缓冲区满了会丢弃新报文

UDP报文大小

  • 理论最大:65535字节
  • 实际限制:1472字节(考虑MTU)
  • 超过MTU会被分片,任何一片丢失都会导致整个报文无法重组

UDP应用

  • DNS、DHCP、NTP、视频直播、在线游戏
  • 实时性要求高的场景

7.2 容易混淆的点

  1. UDP没有发送缓冲区

    • sendto返回成功 ≠ 数据一定能到达
    • 只表示数据交给了网络层
  2. UDP的不可靠性

    • 不是UDP的bug,而是设计选择
    • 为了换取速度和低延迟
  3. UDP的面向数据报

    • 和TCP的面向字节流不同
    • 应用层发多少,UDP就发多少
  4. UDP报文大小限制

    • 不是65535字节就能发
    • 实际受MTU限制,通常1472字节
  5. UDP的全双工

    • 同一个socket既可以发也可以收
    • 不需要建立连接

💬 总结:UDP是一个简单、快速、高效的协议。它放弃了可靠性,换取了速度和低延迟。理解UDP,就理解了为什么有些应用选择UDP而不是TCP。在实时性要求高的场景(视频直播、在线游戏、VoIP),UDP是最佳选择。但如果需要可靠传输(文件下载、邮件、网页),就必须用TCP。两者各有优缺点,没有绝对的好坏,只有是否适合。
👍 点赞、收藏与分享:如果这篇帮你理解了UDP的原理和特点,请点赞收藏!下一篇我们讲TCP,看看TCP如何通过复杂的机制来保证可靠性。

相关推荐
安科士andxe2 小时前
深入解析|安科士1.25G CWDM SFP光模块核心技术,破解中长距离传输痛点
服务器·网络·5g
寻寻觅觅☆5 小时前
东华OJ-基础题-106-大整数相加(C++)
开发语言·c++·算法
YJlio5 小时前
1.7 通过 Sysinternals Live 在线运行工具:不下载也能用的“云端工具箱”
c语言·网络·python·数码相机·ios·django·iphone
fpcc5 小时前
并行编程实战——CUDA编程的Parallel Task类型
c++·cuda
CTRA王大大5 小时前
【网络】FRP实战之frpc全套配置 - fnos飞牛os内网穿透(全网最通俗易懂)
网络
小白同学_C5 小时前
Lab4-Lab: traps && MIT6.1810操作系统工程【持续更新】 _
linux·c/c++·操作系统os
今天只学一颗糖5 小时前
1、《深入理解计算机系统》--计算机系统介绍
linux·笔记·学习·系统架构
2601_949146536 小时前
Shell语音通知接口使用指南:运维自动化中的语音告警集成方案
运维·自动化
儒雅的晴天6 小时前
大模型幻觉问题
运维·服务器
testpassportcn6 小时前
AWS DOP-C02 認證完整解析|AWS DevOps Engineer Professional 考試
网络·学习·改行学it