【嵌入式Linux应用开发基础】网络编程(4):UDP协议

目录

一、UDP 协议概述

二、UDP 协议特点

三、UDP协议的字段格式

四、UDP协议的数据传输过程

五、嵌入式UDP编程核心API

六、UDP 在嵌入式 Linux 中的编程实现

6.1 UDP 服务器代码示例

6.2 UDP 客户端代码示例

七、UDP 协议的应用场景

八、UDP 协议的优缺点

8.1 优点

8.2 缺点

九、嵌入式开发注意事项

9.1. 资源优化

9.2. 错误处理

9.3. 多播实现

9.4. 超时控制

9.5. 交叉编译注意事项

十、调试技巧

十一、性能优化策略

十二、参考资料


UDP(User Datagram Protocol,用户数据报协议)协议是一种基于IP协议的不可靠网络传输协议,它是TCP/IP协议栈中传输层的一部分。与TCP协议相比,UDP协议具有轻量级、无需建立连接、资源消耗少、通信效率高等特点。

一、UDP 协议概述

UDP是一种无连接的传输层协议,与 TCP 不同,它不保证数据的可靠传输、不保证数据的顺序性,也没有拥塞控制机制。UDP 协议具有开销小、传输速度快的特点,适用于对实时性要求较高、对少量数据丢失不太敏感的应用场景。在嵌入式 Linux 应用开发中,UDP 常用于实时音视频传输、游戏、传感器数据采集等领域。

二、UDP 协议特点

  • 无连接:在进行数据传输之前,不需要像 TCP 那样建立连接,发送方只需知道接收方的 IP 地址和端口号,就可以直接发送数据。减少了建立和维护连接的开销,提高了数据传输的速度。
  • 不可靠传输:UDP 不保证数据的可靠传输,数据在传输过程中可能会丢失、重复或乱序。发送方不会等待接收方的确认信息,也不会进行重传操作。因此,应用程序需要自己处理数据丢失和乱序的问题。
  • 面向数据报:UDP 将应用层的数据封装成一个个独立的数据报进行传输,每个数据报都有自己的头部和数据部分。数据报的大小受到网络最大传输单元(MTU)的限制,通常不能超过 65507 字节(包括 UDP 头部 8 字节)
  • 开销小:UDP 头部只有 8 个字节,相比 TCP 头部(通常 20 字节以上)开销更小,这使得 UDP 在传输少量数据时更加高效。

三、UDP协议的字段格式

UDP协议的字段格式包括以下几个部分:

  • 源端口号:16位字段,表示发送方的UDP端口。
  • 目的端口号:16位字段,表示接收方的UDP端口。
  • UDP长度:表示UDP头部和UDP数据段的长度,单位为字节。由于UDP头部为8个字节,因此发送UDP的长度字段最少为8字节。
  • UDP校验和:表示整个UDP字段的CRC16校验和,用于检测数据在传输过程中是否发生错误。校验和字段是可选的,即可以不进行CRC校验,此时校验和部分为全0。

四、UDP协议的数据传输过程

UDP协议的数据传输过程包括封包和解封包两个步骤:

①封包:在发送方,用户发送的数据在传输层增加UDP头部,封装在UDP的数据部分。然后,在IP层增加IP头部数据,将UDP的数据和头部都封装在IP层的数据部分。最后,IP层将数据传输给网络设备的驱动程序,以太网增加头部和尾部后,发送到以太网上。

②解封包:在接收方,驱动程序从以太网上接收到数据后,去除头部和尾部并进行CRC校验。然后,将正确的数据传递给IP层,IP层剥去IP头后进行校验,并将数据发送给其上层UDP层。UDP层将UDP的包头剥去后,根据应用程序的标识符判断是否发送给此应用程序。

五、嵌入式UDP编程核心API

#include <sys/socket.h>// 创建socket
int socket(int domain, int type, int protocol);  // SOCK_DGRAM// 绑定地址
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);// 接收数据(带来源地址)
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);// 发送数据
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

六、UDP 在嵌入式 Linux 中的编程实现

在嵌入式Linux应用开发中,可以使用socket编程接口来实现UDP协议的数据传输。具体步骤如下:

  • 创建socket:使用socket()函数创建一个新的socket,指定使用的地址类型和协议(如PF_INET和SOCK_DGRAM表示使用IPv4和UDP协议)。
  • 绑定地址和端口:使用bind()函数将本地地址和端口号绑定到socket上。
  • 发送数据:使用sendto()函数指定目标地址和端口号发送数据。
  • 接收数据:使用recvfrom()函数接收来自指定地址和端口号的数据。

6.1 UDP 服务器代码示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>#define PORT 8888
#define BUFFER_SIZE 1024int main() {int sockfd;struct sockaddr_in server_addr, client_addr;socklen_t client_addr_len = sizeof(client_addr);char buffer[BUFFER_SIZE];// 创建 UDP 套接字if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {perror("socket creation failed");exit(EXIT_FAILURE);}memset(&server_addr, 0, sizeof(server_addr));memset(&client_addr, 0, sizeof(client_addr));// 填充服务器地址信息server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = INADDR_ANY;server_addr.sin_port = htons(PORT);// 绑定套接字到指定地址和端口if (bind(sockfd, (const struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {perror("bind failed");exit(EXIT_FAILURE);}printf("UDP server listening on port %d...\n", PORT);while (1) {// 接收客户端数据ssize_t recv_len = recvfrom(sockfd, (char *)buffer, BUFFER_SIZE, MSG_WAITALL,(struct sockaddr *)&client_addr, &client_addr_len);if (recv_len < 0) {perror("recvfrom failed");continue;}buffer[recv_len] = '\0';printf("Client: %s\n", buffer);// 发送响应数据给客户端const char *response = "Message received";sendto(sockfd, (const char *)response, strlen(response), MSG_CONFIRM,(const struct sockaddr *)&client_addr, client_addr_len);printf("Response sent to client\n");}// 关闭套接字close(sockfd);return 0;
}

首先创建一个 UDP 套接字,然后将其绑定到指定的 IP 地址和端口。使用 recvfrom 函数接收客户端发送的数据,并使用 sendto 函数发送响应数据给客户端。 

6.2 UDP 客户端代码示例

#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 8888
#define BUFFER_SIZE 1024int main() {int sockfd;struct sockaddr_in server_addr;char buffer[BUFFER_SIZE];// 创建 UDP 套接字if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {perror("socket creation failed");exit(EXIT_FAILURE);}memset(&server_addr, 0, sizeof(server_addr));// 填充服务器地址信息server_addr.sin_family = AF_INET;server_addr.sin_port = htons(PORT);if (inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr) <= 0) {perror("Invalid address/ Address not supported");exit(EXIT_FAILURE);}const char *message = "Hello, server!";// 发送数据到服务器sendto(sockfd, (const char *)message, strlen(message), MSG_CONFIRM,(const struct sockaddr *)&server_addr, sizeof(server_addr));printf("Message sent to server\n");socklen_t server_addr_len = sizeof(server_addr);// 接收服务器响应数据ssize_t recv_len = recvfrom(sockfd, (char *)buffer, BUFFER_SIZE, MSG_WAITALL,(struct sockaddr *)&server_addr, &server_addr_len);if (recv_len < 0) {perror("recvfrom failed");exit(EXIT_FAILURE);}buffer[recv_len] = '\0';printf("Server: %s\n", buffer);// 关闭套接字close(sockfd);return 0;
}

创建一个 UDP 套接字,填充服务器的地址信息,使用 sendto 函数发送数据到服务器,然后使用 recvfrom 函数接收服务器的响应数据。

七、UDP 协议的应用场景

  • 实时音视频传输:如视频会议、在线直播等应用,对实时性要求较高,允许少量数据丢失。UDP 协议的低延迟特性可以保证音视频的流畅播放。
  • 游戏:在网络游戏中,需要快速传输玩家的操作信息,对实时性要求极高。UDP 协议可以满足游戏对低延迟的需求,即使少量数据包丢失,也不会对游戏体验造成太大影响。
  • 传感器数据采集:在物联网应用中,传感器需要实时将采集到的数据发送到服务器。由于传感器数据通常较小且对实时性要求较高,UDP 协议是一种合适的选择。

八、UDP 协议的优缺点

8.1 优点

  • 实时性好:无连接的特性使得数据可以立即发送,不需要等待连接建立和确认过程,减少了传输延迟。
  • 开销小:UDP 头部简单,数据传输的额外开销小,适合传输少量数据。
  • 简单灵活:应用程序可以根据自己的需求对数据进行处理,不需要依赖 UDP 协议提供的复杂机制。

8.2 缺点

  • 不可靠传输:数据可能会丢失、重复或乱序,需要应用程序自己处理这些问题。
  • 缺乏拥塞控制:UDP 协议没有拥塞控制机制,当网络拥塞时,可能会导致大量数据包丢失,影响网络性能。

嵌入式开发注意事项

9.1. 资源优化

  • 设置合理的数据包大小(通常不超过1472字节,避免IP分片)

  • 使用SO_RCVBUF/SO_SNDBUF调优socket缓冲区

9.2. 错误处理

// 检查无效socket描述符
if(fcntl(sockfd, F_GETFL) < 0 && errno == EBADF) {// 处理socket失效
}

9.3. 多播实现

struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr("239.255.255.250");
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));

9.4. 超时控制

struct timeval tv;
tv.tv_sec = 2;  // 2秒超时
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));

9.5. 交叉编译注意事项

  • 确保使用正确的工具链

  • 检查字节序(嵌入式设备多为小端模式)

  • 验证内核UDP协议栈配置

十、调试技巧

使用netcat测试:

# 接收测试
nc -ul 8888# 发送测试
echo "test" | nc -u 192.168.1.100 8888

抓包分析:

tcpdump -i eth0 udp port 8888 -vv -X

查看socket状态:

netstat -anu | grep 8888

十一、性能优化策略

使用多线程处理I/O:

pthread_create(&recv_thread, NULL, udp_recv_handler, &sockfd);

零拷贝技术(Linux 4.1+):

setsockopt(sockfd, SOL_SOCKET, SO_ZEROCOPY, &enable, sizeof(enable));

批量数据发送:

struct mmsghdr msgs[10];
sendmmsg(sockfd, msgs, 10, 0);

掌握这些UDP编程技术后,开发者可以在嵌入式Linux系统中实现高效的网络通信,特别适合需要快速响应、可接受少量数据丢失的物联网应用场景。实际开发中需根据具体硬件资源和应用需求进行参数调优和可靠性增强设计。


十二、参考资料

  • 官方文档与规范:RFC 768这是 UDP 协议的正式规范文档,详细定义了 UDP 协议的功能、报文格式、校验和计算等内容,是深入了解 UDP 协议的权威资料。
  • Linux 网络编程 - UDP 协议详解:该博客对 UDP 协议在 Linux 环境下的特点、首部格式、校验和计算等方面进行了详细的讲解,并对比了 UDP 和 TCP 协议的优劣,同时给出了一些 UDP 在实际应用中的场景分析。

  • 网络协议之 UDP - CSDN 博客:介绍了 UDP 协议的基本概念、特点以及在新兴技术中的应用和面临的挑战,提到了 UDP 在物联网、5G、边缘计算等领域的应用前景,还分析了 UDP 协议在可靠性、安全性和兼容性方面的问题。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/24919.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

视频字幕识别和翻译

下载的视频很多不是汉语的&#xff0c;我们需要用剪映将语音识别出来作为字幕压制到视频中去。 剪映6.0以后语音识别需要收费&#xff0c;但是低版本还是没有问题。 如果想要非汉语字幕转成中文&#xff0c;剪映低版本不提供这样功能。但是&#xff0c;用剪映导出识别字幕&am…

小迪安全-24天-文件管理,显示上传,黑白名单,访问控制

上节课回顾&#xff0c;token问题 没有更新token值&#xff0c;造成了复用 加上这段代码就好了&#xff0c;就不会复用了 文件管理-文件上传 upload.html文件&#xff0c;找ai生成就行 uoload.php接受文件上传的信息 这里在写个临时文件存储换个地方 因为上面临时文件存在c盘…

单入单出队列性能优化(Lock-Free)

摘要&#xff1a;文中首先介绍了有锁线程安全循环队列的基本实现&#xff0c;然后探讨了使用原子变量实现 Lock-Free 队列的优势&#xff0c;能够减少线程之间的数据竞争。接着&#xff0c;介绍了数据对齐的策略&#xff0c;以降低伪共享的概率&#xff0c;随后引入了索引缓存来…

java项目之网络游戏交易系统源码(ssm+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的网络游戏交易系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 本网络游戏交易系统分为管理员…

PyTorch 源码学习:GPU 内存管理之深入分析 CUDACachingAllocator

因引入 expandable_segments 机制&#xff0c;PyTorch 2.1.0 版本发生了较大变化。本文关注的是 PyTorch 原生的 GPU 内存管理机制&#xff0c;故研究的 PyTorch 版本为 2.0.0。代码地址&#xff1a; c10/cuda/CUDACachingAllocator.hc10/cuda/CUDACachingAllocator.cpp 更多内…

【PromptCoder】使用 package.json 生成 cursorrules

【PromptCoder】使用 package.json 生成 cursorrules 在当今快节奏的开发世界中&#xff0c;效率和准确性至关重要。开发者们不断寻找能够优化工作流程、帮助他们更快编写高质量代码的工具。Cursor 作为一款 AI 驱动的代码编辑器&#xff0c;正在彻底改变我们的编程方式。但如…

学习路程五 向量数据库Milvus操作

前序 前面安装好了docker且成功拉取Milvus镜像&#xff0c;启动。通过python成功连接上了数据。接下来就继续更多Milvus的操作 在开始之前&#xff0c;先来简单了解一下向量数据库内一些东西的基本概念 概念描述数据库&#xff08;Database&#xff09;类似与MySQL的database…

SpringBoot 热部署

1、添加 DevTools 依赖 <!-- 热部署依赖 --> <dependency> <groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId> </dependency>2、在IDEA的菜单栏中依次选择“File”→“Settings”&#x…

SOC-ATF 安全启动BL1流程分析(1)

一、ATF 源码下载链接 1. ARM Trusted Firmware (ATF) 官方 GitHub 仓库 GitHub 地址: https://github.com/ARM-software/arm-trusted-firmware 这是 ATF 的官方源码仓库&#xff0c;包含最新的代码、文档和示例。 下载方式&#xff1a; 使用 Git 克隆仓库&#xff1a; git…

汽车无钥匙进入一键启动操作正确步骤

汽车智能无钥匙进入和一键启动的技术在近年来比较成熟&#xff0c;不同车型的操作步骤可能略有不同&#xff0c;但基本的流程应该是通用的&#xff0c;不会因为时间变化而有大的改变。 移动管家汽车一键启动无钥匙进入系统通常是通过携带钥匙靠近车辆&#xff0c;然后触摸门把…

excel单、双字节字符转换函数(中英文输入法符号转换)

在Excel中通常使用函数WIDECHAR和ASC来实现单、双字节字符之间的转换。其中 WIDECHAR函数将所有的字符转换为双字节&#xff0c;ASC函数将所有的字符转换为单字节 首先来解释一下单双字节的含义。单字节一般对应英文输入法的输入&#xff0c;如英文字母&#xff0c;英文输入法…

IP----访问服务器流程

这只是IP的其中一块内容-访问服务器流程&#xff0c;IP还有更多内容可以查看IP专栏&#xff0c;前一段学习内容为IA内容&#xff0c;还有更多内容可以查看IA专栏&#xff0c;可通过以下路径查看IA-----配置NAT-CSDN博客CSDN,欢迎指正 1.访问服务器流程 1.分层 1.更利于标准化…

Ubutu部署WordPress

前言 什么是word press WordPress是一种使用PHP语言开发的建站系统&#xff0c;用户可以在支持PHP和MySQL数据库的服务器上架设WordPress。它是一个开源的内容管理系统&#xff08;CMS&#xff09;&#xff0c;允许用户构建动态网站和博客。现在的WordPress已经强大到几乎可以…

LangChain构建行业知识库实践:从架构设计到生产部署全指南

文章目录 引言:行业知识库的进化挑战一、系统架构设计1.1 核心组件拓扑1.2 模块化设计原则二、关键技术实现2.1 文档预处理流水线2.2 混合检索增强三、领域适配优化3.1 医学知识图谱融合3.2 检索结果重排序算法四、生产环境部署4.1 性能优化方案4.2 安全防护体系五、评估与调优…

Lua的table(表)

Lua表的基本概念 Lua中的表&#xff08;table&#xff09;是一种多功能数据结构&#xff0c;可以用作数组、字典、集合等。表是Lua中唯一的数据结构机制&#xff0c;其他数据结构如数组、列表、队列等都可以通过表来实现。 表的实现 Lua的表由两部分组成&#xff1a; 数组部分…

应对现代生活的健康养生指南

在科技飞速发展的现代社会&#xff0c;人们的生活方式发生了巨大改变&#xff0c;随之而来的是一系列健康问题。快节奏的生活、高强度的工作以及电子产品的过度使用&#xff0c;让我们的身体承受着前所未有的压力。因此&#xff0c;掌握正确的健康养生方法迫在眉睫。 针对久坐不…

使用DeepSeek/chatgpt等AI工具辅助网络协议流量数据包分析

随着deepseek,chatgpt等大模型的能力越来越强大&#xff0c;本文将介绍一下deepseek等LLM在分数流量数据包这方面的能力。为需要借助LLM等大模型辅助分析流量数据包的同学提供参考&#xff0c;也了解一下目前是否有必要继续学习wireshark工具以及复杂的协议知识。 pcap格式 目…

【Linux】CentOS7停服之后配置yum镜像源

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 毛毛张今天分享一个CentOS7系统停服之后&#xff0c;配置yum镜像源的步骤&#xff0c;有坑&#xff01; 文章目录 1.概述2.查看系统架构2.1 查看内核版本2.2 查看lin…

2025-02-26 学习记录--C/C++-C语言 整数格式说明符

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; C语言 整数格式说明符 【例如 】&#x1f380; &#xff1a;在 C 语言中&#xff0c;%ld 是 printf 或 scanf 等格式化输入输出函…

OpenAI开放Deep Research权限,AI智能体大战升级,DeepSeek与Claude迎来新对决

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…