在 Linux 系统中,UDP(User Datagram Protocol,用户数据报协议)是一种无连接的、不可靠的传输层协议,它以其低延迟和高吞吐量著称,广泛应用于实时应用(如视频流、在线游戏、DNS 查询等)。
以下是关于 Linux 中 UDP 的核心概念、配置、调试及编程指南:
核心特性
| 特性 | 说明 |
|---|---|
| 无连接 | 发送数据前不需要建立连接(如 TCP 的三次握手)。 |
| 不可靠 | 不保证数据包到达、不保证顺序、不重传丢失包。 |
| 面向报文 | 保留应用层数据的边界,不会像 TCP 那样进行字节流拆分。 |
| 头部开销小 | UDP 头部仅 8 字节,比 TCP 的 20+ 字节更轻量。 |
| 支持广播/组播 | 天然支持一对多通信。 |
常用网络工具与命令
1 查看 UDP 端口监听状态
# 查看正在监听的 UDP 端口(需要 root 权限) sudo netstat -ulnp # 或使用 ss 命令(推荐,更现代) sudo ss -ulnp
-u: 显示 UDP 协议-l: 显示监听状态-n: 以数字形式显示地址和端口-p: 显示进程信息
2 测试 UDP 连通性
# 使用 nc (netcat) 发送 UDP 数据包 # 发送 "Hello" 到 127.0.0.1 的 9999 端口 echo "Hello" | nc -u -w 1 127.0.0.1 9999 # 监听 UDP 端口(接收端) nc -ul 9999
3 防火墙配置 (iptables/nftables/firewalld)
UDP 端口默认可能被防火墙阻止,需手动开放:
# 使用 firewalld (CentOS/RHEL) sudo firewall-cmd --add-port=9999/udp --permanent sudo firewall-cmd --reload # 使用 iptables sudo iptables -A INPUT -p udp --dport 9999 -j ACCEPT

Linux 内核参数调优(性能优化)
UDP 在高负载下容易丢包,可通过调整内核参数提升性能。
1 关键参数说明
| 参数 | 默认值 | 建议值 | 说明 |
|---|---|---|---|
net.core.rmem_max |
212992 | 16777216 | 接收缓冲区最大大小 |
net.core.rmem_default |
212992 | 262144 | 接收缓冲区默认大小 |
net.core.wmem_max |
212992 | 16777216 | 发送缓冲区最大大小 |
net.core.wmem_default |
212992 | 262144 | 发送缓冲区默认大小 |
net.core.netdev_max_backlog |
1000 | 5000+ | 网卡接收队列长度,防止丢包 |
net.ipv4.udp_mem |
自动 | 手动设置 | UDP 内存使用阈值 |
2 修改方法
编辑 /etc/sysctl.conf 文件:
sudo vim /etc/sysctl.conf
# 增大 UDP 缓冲区 net.core.rmem_max = 16777216 net.core.wmem_max = 16777216 net.core.rmem_default = 262144 net.core.wmem_default = 262144 # 增加网卡接收队列 net.core.netdev_max_backlog = 5000 # 启用 UDP 快速路径(可选) net.ipv4.udp_lro = 1
应用配置:
sudo sysctl -p
C 语言编程示例
1 UDP 服务器端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 9999
#define BUFFER_SIZE 1024
int main() {
int sockfd;
char buffer[BUFFER_SIZE];
struct sockaddr_in serv_addr, cli_addr;
socklen_t len = sizeof(cli_addr);
// 1. 创建 UDP 套接字
if
((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
memset(&serv_addr, 0, sizeof(serv_addr));
memset(&cli_addr, 0, sizeof(cli_addr));
// 2. 配置服务器地址
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
serv_addr.sin_addr.s_addr = INADDR_ANY;
// 3. 绑定地址
if (bind(sockfd, (struct sockaddr )&serv_addr, sizeof(serv_addr)) < 0) {
perror("Bind failed");
exit(EXIT_FAILURE);
}
printf("UDP Server listening on port %d...n", PORT);
// 4. 接收数据
while (1) {
memset(buffer, 0, BUFFER_SIZE);
int n = recvfrom(sockfd, (char )buffer, BUFFER_SIZE, MSG_WAITALL,
(struct sockaddr )&cli_addr, &len);
buffer[n] = '

