当前位置: 首页 > 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.dtcms.com/a/291412.html

相关文章:

  • 二分查找:区间内查询数字的频率
  • 网络协议(三)网络层 IPv4、CIDR(使用子网掩码进行网络划分)、NAT在私网划分中的应用
  • 大模型——上下文工程 (Context Engineering) – 现代 AI 系统的架构基础
  • c语言进阶 自定义类型 枚举,联合
  • 【LeetCode 热题 100】208. 实现 Trie (前缀树)
  • Linux下SPI设备驱动开发
  • 1.Java中的异常有哪些?异常处理机制呢?
  • C# 异常处理
  • 统计与大数据分析专业转型金融行业指南
  • makefile-- 其他函数
  • Linux PCI总线子系统
  • 网络基础DAY15-RSTP
  • OpenGL鼠标控制沿着指定轴旋转
  • linux --frp内网穿透
  • 低速信号设计之 RMII
  • 服务器系统时间不准确怎么办?
  • C++ 中的默认构造函数:非必要,不提供
  • 缓存数组,并遍历循环读取数组
  • springboot实战篇1
  • Windows VS2019 编译 Apache Thrift 0.15.0
  • DigitalOcean 云平台上线 AMD MI325X GPU Droplet 服务器
  • 如何编写假设和约束---SRS软件需求规格指南系列
  • accelerate 在Pycham中执行的设置方法
  • C语言字符串相关函数
  • 【网络编程】网络传输-protobuf
  • Prometheus+altermanager搭配钉钉报警
  • 【PTA数据结构 | C语言版】旅游规划
  • qwen 提示词
  • 试用SAP BTP 02B:试用SAP HANA Cloud
  • Spring处理器和Bean的生命周期