嵌入式Linux网络编程:UDP协议原理与实战代码解析
【本文代码已在Linux平台验证通过】
一、UDP协议核心原理
1.1 UDP vs TCP对比
1.2 UDP报文结构
// UDP头部定义(RFC 768)
struct udp_header {
uint16_t src_port; // 源端口(大端字节序)
uint16_t dst_port; // 目标端口
uint16_t length; // 报文总长度
uint16_t checksum; // 校验和
};
// 数据载荷紧跟头部
二、UDP服务端实现
// UDP服务端示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 6666 // 监听端口
#define BUF_SIZE 1024 // 缓冲区大小
int main(void)
{
int sockfd;
struct sockaddr_in serv_addr, client_addr;
socklen_t addr_len = sizeof(client_addr);
char buffer[BUF_SIZE] = {0};
// 1. 创建UDP套接字
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket创建失败");
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("绑定失败");
close(sockfd);
exit(EXIT_FAILURE);
}
printf("UDP服务端已启动,监听端口: %d\n", PORT);
do{
memset(buffer, 0, sizeof(buffer));
// 4. 接收数据(阻塞模式)
ssize_t recv_len = recvfrom(sockfd, buffer, BUF_SIZE-1, 0,
(struct sockaddr*)&client_addr, &addr_len);
if (recv_len < 0) {
perror("接收失败");
continue;
}
if(strncmp(buffer, "EOF", 3) != 0){
printf("收到来自 %s:%d 的消息: %s\n",
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port),
buffer);
// 5. 构造响应数据
char reply[BUF_SIZE] = {0};
snprintf(reply, sizeof(reply), "已收到 %zd 字节数据", recv_len);
// 6. 发送响应(使用客户端地址)
if (sendto(sockfd, reply, strlen(reply), 0,
(struct sockaddr*)&client_addr, addr_len) < 0) {
perror("发送失败");
}
}else{
// 收到"EOF"消息,结束通信
if (sendto(sockfd, "EOF", 3, 0,
(struct sockaddr*)&client_addr, addr_len) < 0) {
perror("发送失败");
}
}
}while(strncmp(buffer, "EOF", 3) != 0);
close(sockfd);
return 0;
}
三、UDP客户端实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define SERVER_IP "127.0.0.1" // 本地回环地址
#define PORT 6666
#define BUF_SIZE 1024
int main(void)
{
int sockfd;
struct sockaddr_in serv_addr;
char buffer[BUF_SIZE];
// 1. 创建UDP套接字
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket创建失败");
exit(EXIT_FAILURE);
}
// 2. 配置服务器地址
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) {
perror("地址转换失败");
close(sockfd);
exit(EXIT_FAILURE);
}
while (1) {
printf("请输入要发送的消息(输入EOF退出): ");
fgets(buffer, BUF_SIZE, stdin);
buffer[strcspn(buffer, "\n")] = '\0'; // 去除换行符
// 3. 发送数据(无需连接)
ssize_t sent_len = sendto(sockfd, buffer, strlen(buffer), 0,
(struct sockaddr*)&serv_addr,
sizeof(serv_addr));
if (sent_len < 0) {
perror("发送失败");
continue;
}
// 4. 接收响应
memset(buffer, 0, sizeof(buffer));
ssize_t recv_len = recvfrom(sockfd, buffer, BUF_SIZE, 0, NULL, NULL);
if (recv_len < 0) {
perror("接收失败");
continue;
}
if (strncmp(buffer, "EOF", 3) == 0){
break;
}
printf("服务器响应: %s\n", buffer);
}
close(sockfd);
return 0;
}
四、核心API函数详解
4.1 socket()
int socket(int domain, int type, int protocol);
参数 | 说明 | 取值示例 |
---|---|---|
domain | 地址族 | AF_INET(IPv4) |
type | 套接字类型 | SOCK_DGRAM(UDP) |
protocol | 协议类型(通常为0) | 0(自动选择) |
4.2 bind()
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数 | 说明 |
---|---|
sockfd | 套接字描述符 |
addr | 指向地址结构的指针 |
addrlen | 地址结构长度 |
4.3 sendto() / recvfrom()
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
关键参数 | 说明 |
---|---|
buf | 数据缓冲区 |
len | 缓冲区大小 |
dest_addr | 目标地址(sendto专用) |
src_addr | 源地址(recvfrom返回) |
五、编译与测试
5.1 编译命令
# 编译服务端
gcc udp_server.c -o server -Wall -O2
# 编译客户端
gcc udp_client.c -o client -Wall -O2
5.2 运行演示
# 终端1:启动服务端
$ ./server
UDP服务端已启动,监听端口:6666
# 终端2:启动客户端
$ ./client
请输入要发送的消息(输入EOF退出): Hello UDP!
服务器响应: 已收到 10 字节数据
请输入要发送的消息(输入EOF退出): EOF
扩展阅读:
UDP协议RFC文档 | Linux网络编程手册
通过本文,读者可以掌握嵌入式Linux下UDP通信的核心实现方法。在实际物联网项目中,UDP常用于传感器数据采集、实时监控等场景。后续可扩展实现多播、广播等功能!