嵌入式Linux网络编程:UDP协议原理与实战代码解析


嵌入式Linux网络编程:UDP协议原理与实战代码解析

【本文代码已在Linux平台验证通过】


一、UDP协议核心原理

1.1 UDP vs TCP对比

UDP
无连接
不可靠传输
低延迟
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常用于传感器数据采集、实时监控等场景。后续可扩展实现多播、广播等功能!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

银河码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值