rt-thread 使用网络套接字实现UDP客户端源码分享一、UDP协议详解1、核心特性2、UDP数据报结构3、优点4、缺点5、典型应用场景6、 总结二、源码分享一、UDP协议详解UDPUser Datagram Protocol是一种位于网络模型中传输层的协议与TCP传输控制协议一样用于应用程序之间发送数据包。但它与TCP有着显著不同的设计理念和特性。1、核心特性无连接 (Connectionless):在发送数据之前UDP不需要像TCP那样先建立连接三次握手。发送方直接将数据报发送给接收方无需事先协商。接收方也可能在未“同意”接收的情况下收到数据。这使得UDP的开销很小发送速度快。不可靠 (Unreliable):UDP不保证数据报一定能到达目的地。数据报可能在网络中丢失。它不提供数据确认、重传机制或流量控制。发送方不知道数据是否被成功接收。数据报到达的顺序可能与发送顺序不一致UDP也不会重新排序。它只提供非常基本的错误检测通过校验和但不纠正错误。如果校验失败数据报会被丢弃。面向报文 (Datagram-oriented / Message-oriented):UDP是基于报文的协议。应用程序发送给UDP一个完整的报文UDP就将其封装成一个UDP数据报发送出去。在接收端UDP收到一个完整的数据报后将其中的报文原样交给应用程序。它不会像TCP那样将数据拆分成段segments或进行重组。应用程序必须自己处理报文边界。2、UDP数据报结构一个UDP数据报由头部Header和数据Data两部分组成。头部固定为8字节包含四个字段源端口号 (Source Port)(2字节):发送方应用程序使用的端口号。接收方如果需要回复可以使用此端口。如果不需要回复可以设为0。目的端口号 (Destination Port)(2字节):接收方应用程序正在监听的端口号。这是数据报送达的关键标识。长度 (Length)(2字节):指示整个UDP数据报的长度包括头部和数据部分以字节为单位。最小值是8只有头部最大值理论上是65535字节减去IP头部的20字节实际有效数据最大约为65507字节。校验和 (Checksum)(2字节):用于检测数据在传输过程中是否发生错误如比特翻转。计算范围包括伪头部Pseudo-Header包含源IP、目的IP、协议类型、UDP长度、UDP头部和UDP数据部分。如果校验失败接收方通常会丢弃该数据报。此字段是可选的发送方可以置为0表示不计算校验和但不推荐。3、优点开销小速度快: 由于没有连接建立、确认、重传、流量控制等机制UDP的头部更小仅8字节处理起来更快网络开销更低。无连接状态: 服务器可以支持更多的活跃客户端因为它不需要为每个连接维护状态信息。控制粒度细: 应用程序对数据传输拥有更精细的控制权例如自己实现可靠性、重传策略、拥塞控制。支持广播和多播: UDP天然支持将数据报发送到多个主机广播或多播而TCP只能进行点对点通信。4、缺点不可靠: 数据可能丢失、重复或乱序到达。应用程序必须自己处理这些问题。无拥塞控制: 发送方可能以过快的速度发送数据淹没网络或接收方导致丢包加剧和网络拥塞。安全性较低: 没有内置的加密或认证机制虽然可以在应用层实现如DTLS。5、典型应用场景UDP的特性决定了它适用于那些可以容忍一定数据丢失但对低延迟和速度要求极高的场景实时音视频流 (Real-time Audio/Video Streaming):如视频会议Zoom, Teams、在线直播、VoIP网络电话。丢失少量数据包可能只导致短暂的画质下降或声音卡顿但等待TCP重传会导致无法接受的延迟和卡顿。在线游戏 (Online Gaming):玩家的位置、动作等状态更新需要极低的延迟。偶尔丢失一个位置更新包可能影响不大或者可以通过插值预测但延迟高会导致游戏体验极差。通常游戏会在UDP之上实现自己的可靠性机制。DNS (域名系统):DNS查询通常非常简短且要求快速响应。UDP的简单高效非常适合。如果响应太大超过512字节或未收到响应客户端会回退到使用TCP。DHCP (动态主机配置协议):用于自动获取IP地址。通信发生在客户端尚未有IP地址时使用UDP广播非常合适。SNMP (简单网络管理协议):用于网络设备监控和管理。轮询设备状态信息通常使用UDP。TFTP (简单文件传输协议):一种非常简单的文件传输协议常用于网络启动如无盘工作站。广播/多播应用:如网络时间协议NTP、某些路由协议RIP等。6、 总结UDP是一个简单、轻量级、无连接的传输层协议。它牺牲了可靠性不保证交付、不保证顺序和复杂的控制机制无连接管理、无流量控制、无拥塞控制换取了低开销和高速度。这使得UDP成为对延迟敏感且能容忍少量数据丢失的应用的理想选择。二、源码分享/* * 命令调用格式udpclient URL PORT [COUNT 10] * URL服务器地址 PORT端口号 COUNT可选参数 默认为 10 * 程序功能发送 COUNT 条数据到服务远端 */#includertthread.h#includesys/socket.h/* 使用BSD socket需要包含sockets.h头文件 */#includenetdb.h#includestring.h#includefinsh.hconstcharsend_data[]This is UDP Client from RT-Thread.\n;/* 发送用到的数据 */voidudpclient(intargc,char**argv){intsock,port,count;structhostent*host;structsockaddr_inserver_addr;constchar*url;if(argc3){rt_kprintf(Usage: udpclient URL PORT [COUNT 10]\n);rt_kprintf(Like: tcpclient 192.168.12.44 5000\n);return;}urlargv[1];portstrtoul(argv[2],0,10);if(argc3)countstrtoul(argv[3],0,10);elsecount10;/* 通过函数入口参数url获得host地址如果是域名会做域名解析 */host(structhostent*)gethostbyname(url);/* 创建一个socket类型是SOCK_DGRAMUDP类型 */if((socksocket(AF_INET,SOCK_DGRAM,0))-1){rt_kprintf(Socket error\n);return;}/* 初始化预连接的服务端地址 */server_addr.sin_familyAF_INET;server_addr.sin_porthtons(port);server_addr.sin_addr*((structin_addr*)host-h_addr);rt_memset((server_addr.sin_zero),0,sizeof(server_addr.sin_zero));/* 总计发送count次数据 */while(count){/* 发送数据到服务远端 */sendto(sock,send_data,strlen(send_data),0,(structsockaddr*)server_addr,sizeof(structsockaddr));/* 线程休眠一段时间 */rt_thread_delay(50);/* 计数值减一 */count--;}/* 关闭这个socket */closesocket(sock);}MSH_CMD_EXPORT(udpclient,a udp client sample);