📘 Linux UDP Socket 学习指南
适合初学者理解 UDP 原理与在 Linux 下编写 UDP 程序。
对比 TCP,它更轻量、更快,但不保证可靠传输。
🧠 一、UDP 是什么?
1. UDP(User Datagram Protocol)
UDP 是一种无连接、不可靠的传输层协议。
| 特性 | 说明 |
|---|---|
| 无连接 | 通信前不需要三次握手 |
| 不可靠 | 不保证数据按顺序、不保证送达 |
| 面向报文 | 一次发送/接收对应一个完整数据包 |
| 轻量快速 | 头部开销小,适合实时通信 |
可以理解为:
TCP 像“打电话”,需要建立连接;
UDP 像“发短信”,直接发出去,不管对方是否收到。
🧩 二、UDP 通信流程
UDP 通信流程比 TCP 简单得多:
| 阶段 | 客户端 | 服务端 |
|---|---|---|
| 创建Socket | socket() | socket() |
| 绑定端口 | (可选) | bind() |
| 发送/接收 | sendto() / recvfrom() | sendto() / recvfrom() |
| 关闭Socket | close() | close() |
没有 listen()、accept()、connect()。
🧱 三、UDP 服务端与客户端示例
✅ 服务端(udp_server.c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>int main() {int sockfd;struct sockaddr_in server_addr, client_addr;socklen_t client_len = sizeof(client_addr);char buffer[1024];// 1. 创建UDP Socketsockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {perror("socket error");exit(1);}// 2. 绑定IP和端口server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = INADDR_ANY;server_addr.sin_port = htons(5000);if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {perror("bind error");exit(1);}printf("UDP server listening on port 5000...\n");// 3. 接收数据while (1) {int len = recvfrom(sockfd, buffer, sizeof(buffer), 0,(struct sockaddr*)&client_addr, &client_len);buffer[len] = '\0';printf("Received from %s:%d: %s\n",inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), buffer);// 4. 回发消息sendto(sockfd, "Hello from UDP server", 22, 0,(struct sockaddr*)&client_addr, client_len);}close(sockfd);return 0;
}
✅ 客户端(udp_client.c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>int main() {int sockfd;struct sockaddr_in server_addr;char buffer[1024];// 1. 创建UDP Socketsockfd = socket(AF_INET, SOCK_DGRAM, 0);// 2. 服务器信息server_addr.sin_family = AF_INET;server_addr.sin_port = htons(5000);inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);// 3. 发送数据sendto(sockfd, "Hello UDP Server", 17, 0,(struct sockaddr*)&server_addr, sizeof(server_addr));// 4. 接收回应socklen_t addr_len = sizeof(server_addr);int len = recvfrom(sockfd, buffer, sizeof(buffer), 0,(struct sockaddr*)&server_addr, &addr_len);buffer[len] = '\0';printf("From server: %s\n", buffer);close(sockfd);return 0;
}
🧰 编译与运行
gcc udp_server.c -o udp_server
gcc udp_client.c -o udp_client
./udp_server
# 另一个终端运行客户端
./udp_client
⚙️ 四、UDP 常用函数讲解
| 函数名 | 功能 | 说明 |
|---|---|---|
socket() |
创建Socket | SOCK_DGRAM 表示UDP |
bind() |
绑定本地地址和端口 | 通常服务端使用 |
sendto() |
向指定地址发送数据 | 无需建立连接 |
recvfrom() |
接收数据并返回来源地址 | |
close() |
关闭Socket |
🧮 五、UDP Socket 常用选项
1. 设置套接字参数
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
2. 常用选项表
| 选项名 | 说明 | 使用场景 |
|---|---|---|
SO_REUSEADDR |
允许端口重用 | 避免重启时报错 |
SO_BROADCAST |
允许广播发送 | 局域网广播 |
SO_RCVBUF / SO_SNDBUF |
调整缓冲区大小 | 优化性能 |
IP_MULTICAST_TTL |
组播跳数 | 多播场景 |
🌍 六、UDP 的三种通信模式
| 模式 | 特点 | 示例 |
|---|---|---|
| 单播(Unicast) | 一对一通信 | 普通客户端和服务器 |
| 广播(Broadcast) | 一对多通信 | 局域网内同时通知 |
| 组播(Multicast) | 特定组通信 | IPTV、视频会议 |
📡 七、UDP 与 TCP 的区别总结
| 特性 | TCP | UDP |
|---|---|---|
| 连接方式 | 面向连接 | 无连接 |
| 可靠性 | 保证顺序与可靠性 | 不保证顺序或可靠性 |
| 传输单位 | 字节流 | 数据报 |
| 速度 | 较慢 | 快速 |
| 适用场景 | 文件传输、HTTP | 实时通信、语音、视频、DNS |
🔍 八、UDP 调试与测试命令
| 命令 | 功能 |
|---|---|
netstat -anu |
查看UDP端口 |
ss -u -l |
查看UDP监听 |
tcpdump -i eth0 udp |
抓UDP包 |
nc -u 127.0.0.1 5000 |
使用 netcat 测试UDP服务 |
📈 九、UDP 实践建议
- 先从本地单播(127.0.0.1)开始练习。
- 再尝试广播(如 255.255.255.255)通信。
- 了解组播(Multicast)通信。
- 使用
tcpdump观察 UDP 包的内容。 - 对比 TCP 程序,理解“无连接”带来的影响。
🧭 十、进阶学习方向
| 阶段 | 学习内容 |
|---|---|
| 初级 | UDP 单播、广播编程 |
| 中级 | 组播、多播(Multicast)编程 |
| 高级 | RTP、QUIC、实时音视频传输协议 |
| 专业 | 实现可靠UDP(RUDP)、应用层重传机制 |
📚 十一、参考资料
-
《Unix 网络编程(卷1)》—— W. Richard Stevens
-
man 手册:
man 2 socket man 2 sendto man 7 udp -
Linux 内核头文件:
/usr/include/linux/udp.h