当前位置: 首页 > news >正文

网络编程之 UDP:用户数据报协议详解与实战

UDP(User Datagram Protocol)作为传输层的重要协议,以其无连接、不可靠但高效的特性,在实时通信、流媒体等领域有着广泛应用。本文将深入解析 UDP 的核心概念,并通过实战案例展示其编程实现。

一、UDP 协议特性

UDP 与 TCP 相比,具有以下特点: 

  • 无连接:通信前无需建立连接,直接发送数据。
  • 不可靠:不保证数据的可靠传输,可能丢包、乱序。
  • 高效:无需维护连接状态,开销小,适合实时性要求高的场景。
  • 面向数据报:数据以独立的数据包形式传输,边界清晰。
二、UDP 编程框架

UDP 编程采用 C/S 模式,基本框架如下: 

服务器端

socket() → bind() → recvfrom() → close()

客户端

socket() → [bind()] → sendto() → close()

关键函数

  • socket(PF_INET, SOCK_DGRAM, 0):创建 UDP 套接字。
  • sendto():发送数据报。
  • recvfrom():接收数据报。
三、UDP 核心函数解析
1. sendto() 函数
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

  • 功能:向指定目标发送数据。
  • 参数
    • dest_addr:目标地址(必选)。
    • addrlen:地址长度。
2. recvfrom() 函数
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);

  • 功能:接收数据并获取发送方地址(可选)。
  • 参数
    • src_addr:发送方地址(若为 NULL 则忽略)。
    • addrlen:地址长度指针。
四、UDP 编程实战
1. UDP 测试程序

服务器端代码(udp_server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>#define PORT 50000
#define BUF_SIZE 1024int main() {// 创建 UDP 套接字int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {perror("socket creation failed");exit(EXIT_FAILURE);}// 设置服务器地址struct sockaddr_in serv_addr;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);// 绑定套接字if (bind(sockfd, (const struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {perror("bind failed");exit(EXIT_FAILURE);}printf("UDP Server listening on port %d...\n", PORT);// 接收数据char buffer[BUF_SIZE];struct sockaddr_in cli_addr;socklen_t len = sizeof(cli_addr);while (1) {memset(buffer, 0, BUF_SIZE);ssize_t n = recvfrom(sockfd, (char *)buffer, BUF_SIZE,MSG_WAITALL, (struct sockaddr *)&cli_addr,&len);if (n < 0) {perror("recvfrom failed");continue;}printf("Client [%s:%d]: %s\n",inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port),buffer);// 回显消息sendto(sockfd, (const char *)buffer, strlen(buffer),MSG_CONFIRM, (const struct sockaddr *)&cli_addr, len);}close(sockfd);return 0;
}

客户端代码(udp_client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>#define SERVER_IP "127.0.0.1"
#define PORT 50000
#define BUF_SIZE 1024int main() {// 创建 UDP 套接字int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {perror("socket creation failed");exit(EXIT_FAILURE);}// 设置服务器地址struct sockaddr_in serv_addr;memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(PORT);serv_addr.sin_addr.s_addr = inet_addr(SERVER_IP);char buffer[BUF_SIZE];socklen_t len = sizeof(serv_addr);while (1) {printf("Enter message (or 'exit' to quit): ");fgets(buffer, BUF_SIZE, stdin);buffer[strcspn(buffer, "\n")] = 0;  // 去除换行符if (strcmp(buffer, "exit") == 0) {break;}// 发送数据sendto(sockfd, (const char *)buffer, strlen(buffer),MSG_CONFIRM, (const struct sockaddr *)&serv_addr, len);// 接收响应memset(buffer, 0, BUF_SIZE);ssize_t n = recvfrom(sockfd, (char *)buffer, BUF_SIZE,MSG_WAITALL, (struct sockaddr *)&serv_addr,&len);if (n < 0) {perror("recvfrom failed");continue;}printf("Server: %s\n", buffer);}close(sockfd);return 0;
}
2. 点对点聊天程序

基于 UDP 的点对点聊天程序需要双方同时作为客户端和服务器:

// 简化版点对点聊天程序框架
void chat_client() {int sockfd = socket(AF_INET, SOCK_DGRAM, 0);// 初始化地址...// 创建两个线程:一个接收消息,一个发送消息pthread_t recv_thread, send_thread;pthread_create(&recv_thread, NULL, receive_messages, &sockfd);pthread_create(&send_thread, NULL, send_messages, &sockfd);pthread_join(recv_thread, NULL);pthread_join(send_thread, NULL);close(sockfd);
}
五、UDP 聊天室实现
需求分析
  • 注册机制:客户端连接时向服务器注册。
  • 消息转发:服务器将消息广播给所有在线客户端。
  • 下线通知:客户端下线时通知其他用户。
核心设计

服务器端

// 客户端信息结构体
typedef struct {struct sockaddr_in addr;char username[50];int online;
} Client;Client clients[MAX_CLIENTS];  // 客户端列表// 处理注册请求
void handle_registration(int sockfd, struct sockaddr_in *client_addr, char *username) {// 查找空位或已有客户端// 更新客户端信息// 通知其他客户端
}// 处理消息转发
void handle_message(int sockfd, struct sockaddr_in *client_addr, char *message) {// 查找发送者// 转发消息给所有在线客户端
}// 主循环
while (1) {recvfrom(sockfd, buffer, BUF_SIZE, 0, (struct sockaddr *)&client_addr, &len);// 解析消息类型(注册、消息、下线)// 调用相应处理函数
}

客户端

// 发送线程
void *send_messages(void *arg) {int sockfd = *(int *)arg;struct sockaddr_in server_addr;// 初始化服务器地址...// 注册用户名sendto(sockfd, username, strlen(username), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));// 循环发送消息while (1) {fgets(message, BUF_SIZE, stdin);sendto(sockfd, message, strlen(message), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));}
}// 接收线程
void *receive_messages(void *arg) {int sockfd = *(int *)arg;// 循环接收消息并打印
}
六、UDP 与 TCP 的对比
特性UDPTCP
连接状态无连接面向连接
可靠性不可靠(可能丢包)可靠(保证交付)
传输效率高(开销小)低(维护连接开销大)
应用场景实时音视频、DNS文件传输、HTTP
七、总结

UDP 以其简单高效的特点,在需要快速传输、实时性要求高的场景中表现出色。本文从 UDP 的基本特性出发,详细解析了其编程框架和核心函数,并通过三个实战案例(测试程序、点对点聊天、聊天室)展示了 UDP 的应用方式。

虽然 UDP 不保证可靠传输,但在许多场景下,这种 “不可靠” 恰恰成为其优势。通过合理的上层设计(如重传机制、消息确认),UDP 也能在一定程度上弥补其不足,满足复杂应用的需求。

http://www.xdnf.cn/news/1165105.html

相关文章:

  • 嵌入式八股文之 struct 和 union 的区别、大厂真题1、头文件中的#ifdef/#define/#endif作用是什么?
  • React探索高性能Tree树组件实现——react-window、react-vtree
  • Kafka 如何优雅实现 Varint 和 ZigZag 编码
  • AXI接口学习
  • 在github上搭建自己主页
  • Spring Boot 3核心技术面试指南:从迁移升级到云原生实战,9轮技术攻防(含架构解析)
  • 添加状态信息
  • Linux find命令:强大的文件搜索工具
  • 代码审计Tabby安装教程
  • 神经网络——归一化层
  • nextjs编程式跳转
  • LinkedList的模拟实现(双向链表Java)
  • Java注解家族--`@ResponseBody`
  • 神经网络——线性层
  • 【c++】leetcode5 最长回文子串
  • 蚂蚁数科AI数据产业基地正式投产,携手苏州推进AI产业落地
  • 奥比中光深度相机开发
  • 感知机-梯度下降法
  • 141 个 LangChain4j Maven 组件分类解析、多场景实战攻略
  • 一个月掌握数据结构与算法:高效学习计划
  • hot100回归复习(算法总结1-38)
  • 零拷贝技术(Zero-Copy)
  • 网络协议(四)网络层 路由协议
  • C++基于libmodbus库实现modbus TCP/RTU通信
  • 大模型——上下文工程 (Context Engineering) – 现代 AI 系统的架构基础
  • C# 实现:动态规划解决 0/1 背包问题
  • iOS开发 Swift 速记2:三种集合类型 Array Set Dictionary
  • OCR 身份识别:让身份信息录入场景更高效安全
  • 如何使用终端查看任意Ubuntu的版本信息
  • 用 Three.js 实现 PlayCanvas 风格 PBR 材质教程(第二篇):核心参数与光照模型