当前位置: 首页 > 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.lryc.cn/news/594927.html

相关文章:

  • 19.TaskExecutor与ResourceManager建立连接
  • Openlayers 面试题及答案180道(161-180)
  • 线上问题排查之【CPU飙高100%】
  • 在幸狐RV1106板子上用gcc14.2本地编译安装mysql-8.0.42数据库
  • 一维DP深度解析
  • ElasticSearch是什么
  • 如何使用Ansible一键部署Nacos集群?
  • Android 蓝牙通讯全解析:从基础到实战
  • 【STM32】485接口原理
  • 元图 CAD:PDF 与 CAD 格式互转的完美解决方案
  • 部署 Zabbix 企业级分布式监控
  • WPF 初始界面启动时播放背景音乐
  • 合并pdf工具下载
  • Redis进阶--缓存
  • 如何使用python网络爬虫批量获取公共资源数据
  • 微软CEO Satya Nadella提出AI重构法则:从范式跃迁到社会盈余
  • 本地生活服务 app 同城信息发布系统搭建
  • delphi disqlite3 操作sqlite
  • C# 计算梯形面积和周长的程序(Program to calculate area and perimeter of Trapezium)
  • 在Windows Server 2012 R2中安装与配置IIS服务并部署mssql靶机教程
  • 【世纪龙科技】新能源汽车概论-汽车教学数字课程资源
  • 如何编写假设和约束---SRS软件需求规格指南系列
  • 概率论与数理统计(八)
  • 【跨国数仓迁移最佳实践2】MaxCompute SQL执行引擎对复杂类型处理全面重构,保障客户从BigQuery平滑迁移
  • java和ptyhon对比
  • C# Lambdab表达式 Var 类
  • PyQt5—QInputDialog 学习笔记
  • Iridium Certus 9704 卫星物联网开发套件
  • uniapp app pdf.js报错:Uncaught SyntaxError:Unexpected token ‘{‘
  • UART串口