【C++网络编程】第5篇:UDP与广播通信

一、UDP协议核心特性

1. UDP vs TCP

​特性 ​UDP​TCP
连接方式无连接面向连接(三次握手)
可靠性不保证数据到达或顺序可靠传输(超时重传、顺序控制)
传输效率低延迟,高吞吐相对较低(因握手和确认机制)
适用场景实时音视频、广播、在线游戏文件传输、Web请求、数据库操作

2. UDP数据包结构

  • **首部(8字节)**​:
| 源端口(2) | 目标端口(2) |
| 数据包长度(2) | 校验和(2) |
  • 数据载荷:最大长度受限于IPv4的MTU(通常1500字节)​。

3. 不同方式介绍

​单播(Unicast)​:1 对 1(普通 UDP/TCP 通信)。
​广播(Broadcast)​:1 对同一子网内所有设备。
​组播(Multicast)​:1 对一组指定的设备(跨子网)。


二、UDP单播通信实现

1. UDP服务器与客户端流程

服务器:socket() → bind() → recvfrom() → sendto()
客户端:socket() → sendto() → recvfrom()

2. 完整代码示例

​UDP服务器(接收并回复)​

#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>  
#pragma comment(lib, "ws2_32.lib")int main() {WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {std::cerr << "WSAStartup failed!" << std::endl;return 1;}SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);sockaddr_in serverAddr{};serverAddr.sin_family = AF_INET;serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);serverAddr.sin_port = htons(8080);bind(sock, (sockaddr*)&serverAddr, sizeof(serverAddr));std::cout << "UDP Server listening on port 8080..." << std::endl;char buffer[1024];sockaddr_in clientAddr{};int clientAddrLen = sizeof(clientAddr);while (true) {int bytesReceived = recvfrom(sock, buffer, sizeof(buffer), 0,(sockaddr*)&clientAddr, &clientAddrLen);if (bytesReceived == SOCKET_ERROR) {std::cerr << "recvfrom failed: " << WSAGetLastError() << std::endl;continue;}char clientIp[INET_ADDRSTRLEN] = { 0 };if (InetNtopA(AF_INET,                            // IPv4&clientAddr.sin_addr,               // 输入地址结构体clientIp,                           // 输出缓冲区sizeof(clientIp)                    // 缓冲区大小) == NULL) {std::cerr << "IP conversion failed: " << WSAGetLastError() << std::endl;strcpy_s(clientIp, "unknown");      // 错误时显示 "unknown"}std::cout << "Received " << bytesReceived << " bytes from "<< clientIp << ":"                  // 使用转换后的 IP 字符串<< ntohs(clientAddr.sin_port) << std::endl;// 原样返回数据sendto(sock, buffer, bytesReceived, 0,(sockaddr*)&clientAddr, clientAddrLen);}closesocket(sock);WSACleanup();return 0;
}

UDP客户端(发送消息)​

#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h> 
#pragma comment(lib, "ws2_32.lib")int main() {WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {std::cerr << "WSAStartup failed!" << std::endl;return 1;}SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);sockaddr_in serverAddr{};serverAddr.sin_family = AF_INET;inet_pton(AF_INET, "127.0.0.1", &(serverAddr.sin_addr.s_addr));serverAddr.sin_port = htons(8080);const char* message = "Hello UDP Server!";sendto(sock, message, strlen(message), 0,(sockaddr*)&serverAddr, sizeof(serverAddr));char buffer[1024];int bytesReceived = recvfrom(sock, buffer, sizeof(buffer), 0, nullptr, nullptr);if (bytesReceived > 0) {std::cout << "Server echoed: " << std::string(buffer, bytesReceived) << std::endl;}closesocket(sock);WSACleanup();return 0;
}

测试结果
在这里插入图片描述


三、UDP广播通信

1. 广播地址与设置

  • 广播地址:255.255.255.255(全局广播)或子网广播地址(如192.168.1.255)。
  • 套接字选项:启用SO_BROADCAST
int enable = 1;
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&enable, sizeof(enable));

2. 广播发送端代码

#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>  
#pragma comment(lib, "ws2_32.lib")int main() {WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {std::cerr << "WSAStartup failed!" << std::endl;return 1;}SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);// 启用广播int enable = 1;setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&enable, sizeof(enable));sockaddr_in broadcastAddr{};broadcastAddr.sin_family = AF_INET;inet_pton(AF_INET, "127.0.0.1", &(broadcastAddr.sin_addr.s_addr));broadcastAddr.sin_port = htons(8080);const char* message = "Broadcast Message!";sendto(sock, message, strlen(message), 0,(sockaddr*)&broadcastAddr, sizeof(broadcastAddr));closesocket(sock);WSACleanup();return 0;
}

3. 服务器端修改部分

        std::cout << "Received " << bytesReceived << " bytes from "<< clientIp << ":"                  // 使用转换后的 IP 字符串<< ntohs(clientAddr.sin_port) << std::endl;std::cout << "Datas:" << std::string(buffer, bytesReceived) << std::endl;

4. 测试结果

在这里插入图片描述


四、UDP组播(Multicast)​

1. 组播地址范围

  • IPv4:224.0.0.0 ~ 239.255.255.255(如239.255.0.1)。

2. 接收端

#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")int main() {WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {std::cerr << "WSAStartup failed!" << std::endl;return 1;}// 创建 UDP 套接字SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);if (sock == INVALID_SOCKET) {std::cerr << "socket() failed: " << WSAGetLastError() << std::endl;WSACleanup();return 1;}// 设置端口复用(允许其他进程绑定相同端口)int reuse = 1;if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,(char*)&reuse, sizeof(reuse)) == SOCKET_ERROR) {std::cerr << "setsockopt(SO_REUSEADDR) failed: " << WSAGetLastError() << std::endl;closesocket(sock);WSACleanup();return 1;}// 绑定到本地端口sockaddr_in localAddr{};localAddr.sin_family = AF_INET;localAddr.sin_addr.s_addr = htonl(INADDR_ANY);localAddr.sin_port = htons(8080);if (bind(sock, (sockaddr*)&localAddr, sizeof(localAddr)) == SOCKET_ERROR) {std::cerr << "bind() failed: " << WSAGetLastError() << std::endl;closesocket(sock);WSACleanup();return 1;}// 加入组播组ip_mreq mreq{};if (inet_pton(AF_INET, "239.255.255.250", &(mreq.imr_multiaddr.s_addr)) != 1) {std::cerr << "inet_pton() failed for multicast address" << std::endl;closesocket(sock);WSACleanup();return 1;}mreq.imr_interface.s_addr = htonl(INADDR_ANY);  // 使用默认网络接口if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,(char*)&mreq, sizeof(mreq)) == SOCKET_ERROR) {std::cerr << "setsockopt(IP_ADD_MEMBERSHIP) failed: " << WSAGetLastError() << std::endl;closesocket(sock);WSACleanup();return 1;}std::cout << "Listening for multicast on 239.255.255.250:8080..." << std::endl;char buffer[1024];sockaddr_in senderAddr{};int senderAddrLen = sizeof(senderAddr);while (true) {// 接收数据int bytesReceived = recvfrom(sock, buffer, sizeof(buffer) - 1, 0,(sockaddr*)&senderAddr, &senderAddrLen);if (bytesReceived == SOCKET_ERROR) {std::cerr << "recvfrom() failed: " << WSAGetLastError() << std::endl;continue;}// 显示来源信息char senderIp[INET_ADDRSTRLEN] = { 0 };inet_ntop(AF_INET, &senderAddr.sin_addr, senderIp, INET_ADDRSTRLEN);std::cout << "Received " << bytesReceived << " bytes from "<< senderIp << ":" << ntohs(senderAddr.sin_port) << std::endl;// 安全处理数据(防止缓冲区溢出)buffer[bytesReceived] = '\0';  // 添加字符串终止符std::cout << "Data: " << buffer << std::endl;}// 退出时清理(虽然 while(true) 会阻止执行到这里)closesocket(sock);WSACleanup();return 0;
}

3. 发送端

#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")int main() {// 初始化 WinsockWSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {std::cerr << "WSAStartup failed: " << WSAGetLastError() << std::endl;return 1;}// 创建 UDP 套接字SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);if (sock == INVALID_SOCKET) {std::cerr << "socket() failed: " << WSAGetLastError() << std::endl;WSACleanup();return 1;}// 设置组播 TTL(控制传输范围)int ttl = 32;if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL,(char*)&ttl, sizeof(ttl)) == SOCKET_ERROR) {std::cerr << "setsockopt(IP_MULTICAST_TTL) failed: " << WSAGetLastError() << std::endl;closesocket(sock);WSACleanup();return 1;}// 构建组播目标地址sockaddr_in multicastAddr{};multicastAddr.sin_family = AF_INET;multicastAddr.sin_port = htons(8080); // 目标端口// 转换组播地址if (inet_pton(AF_INET, "239.255.255.250", &multicastAddr.sin_addr.s_addr) != 1) {std::cerr << "inet_pton() failed for multicast address" << std::endl;closesocket(sock);WSACleanup();return 1;}// 发送数据const char* msg = "Hello Multicast!";int msgLen = static_cast<int>(strlen(msg));int bytesSent = sendto(sock, msg, msgLen, 0,(sockaddr*)&multicastAddr, sizeof(multicastAddr));if (bytesSent == SOCKET_ERROR) {std::cerr << "sendto() failed: " << WSAGetLastError() << std::endl;}else if (bytesSent != msgLen) {std::cerr << "sendto() partial send: " << bytesSent << "/" << msgLen << std::endl;}else {std::cout << "Successfully sent " << bytesSent<< " bytes to multicast group 239.255.255.250:8080" << std::endl;}// 清理资源closesocket(sock);WSACleanup();return 0;
}

4. 测试结果

在这里插入图片描述


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

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

相关文章

MOSN(Modular Open Smart Network)是一款主要使用 Go 语言开发的云原生网络代理平台

前言 大家好&#xff0c;我是老马。 sofastack 其实出来很久了&#xff0c;第一次应该是在 2022 年左右开始关注&#xff0c;但是一直没有深入研究。 最近想学习一下 SOFA 对于生态的设计和思考。 sofaboot 系列 SOFABoot-00-sofaboot 概览 SOFABoot-01-蚂蚁金服开源的 s…

微信小程序日常开发问题整理

微信小程序日常开发问题整理 1 切换渲染模式1.1 WebView 的链接在模拟器可以打开&#xff0c;手机上无法打开。 1 切换渲染模式 1.1 WebView 的链接在模拟器可以打开&#xff0c;手机上无法打开。 在 app.json 中看到如下配置项&#xff0c;那么当前项目就是 keyline 渲染模式…

【Altium Designer】铜皮编辑

一、动态铜皮与静态铜皮的区分与切换 动态铜皮&#xff08;活铜&#xff09;&#xff1a; 通过快捷键 PG 创建&#xff0c;支持自动避让其他网络对象&#xff0c;常用于大面积铺铜&#xff08;如GND或电源网络&#xff09;。修改动态铜皮后&#xff0c;需通过 Tools → Polygo…

Java「Deque」 方法详解:从入门到实战

Java Deque 各种方法解析&#xff1a;从入门到实战 在 Java 编程中&#xff0c;Deque&#xff08;双端队列&#xff09;是一个功能强大的数据结构&#xff0c;允许开发者从队列的两端高效地添加、删除和检查元素。作为 java.util 包中的一部分&#xff0c;Deque 接口继承自 Qu…

ffmpeg+QOpenGLWidget显示视频

​一个基于 ‌FFmpeg 4.x‌ 和 QOpenGLWidget的简单视频播放器代码示例&#xff0c;实现视频解码和渲染到 Qt 窗口的功能。 1&#xff09;ffmpeg库界面&#xff0c;视频解码支持软解和硬解方式。 硬解后&#xff0c;硬件解码完成需要将数据从GPU复制到CPU。优先采用av_hwf…

深入解析嵌入式内核:从架构到实践

一、嵌入式内核概述 嵌入式内核是嵌入式操作系统的核心组件&#xff0c;负责管理硬件资源、调度任务、处理中断等关键功能。其核心目标是在资源受限的环境中提供高效、实时的控制能力。与通用操作系统不同&#xff0c;嵌入式内核通常具有高度可裁剪性、实时性和可靠性&#xff…

20250324-使用 `nltk` 的 `sent_tokenize`, `word_tokenize、WordNetLemmatizer` 方法时报错

解决使用 nltk 的 sent_tokenize, word_tokenize、WordNetLemmatizer 方法时报错问题 第 2 节的手动方法的法1可解决大部分问题&#xff0c;可首先尝试章节 2 的方法 1. nltk.download(‘punkt_tab’) LookupError: *******************************************************…

『 C++ 』多线程同步:条件变量及其接口的应用实践

文章目录 条件变量概述条件变量简介条件变量的基本用法 案例&#xff1a;两个线程交替打印奇偶数代码解释 std::unique_lock::try_lock_until 介绍代码示例代码解释注意事项 std::condition_variable::wait 详细解析与示例std::condition_variable::wait 接口介绍代码示例代码解…

【VolView】纯前端实现CT三维重建-CBCT

文章目录 什么是CBCTCBCT技术路线使用第三方工具使用Python实现使用前端实现 纯前端实现方案优缺点使用VolView实现CBCT VolView的使用1.克隆代码2.配置依赖3.运行4.效果 进阶&#xff1a;VolView配合Python解决卡顿1.修改VtkThreeView.vue2.新增Custom3DView.vue3.Python生成s…

debug - 安装.msi时,为所有用户安装程序

文章目录 debug - 安装.msi时&#xff0c;为所有用户安装程序概述笔记试试在目标.msi后面直接加参数的测试 备注备注END debug - 安装.msi时&#xff0c;为所有用户安装程序 概述 为了测试&#xff0c;装了一个test.msi. 安装时&#xff0c;只有安装路径的选择&#xff0c;没…

Java Stream两种list判断字符串是否存在方案

这里写自定义目录标题 背景初始化方法一、filter过滤方法二、anyMatch匹配 背景 在项目开发中&#xff0c;经常遇到筛选list中是否包含某个子字符串&#xff0c;有多种方式&#xff0c;本篇主要介绍stream流的filter和anyMatch两种方案&#xff0c;记录下来&#xff0c;方便备…

DeepSeek vs 通义大模型:谁将主导中国AI的未来战场?

当你在深夜调试代码时,是否幻想过AI伙伴能真正理解你的需求?当企业面对海量数据时,是否期待一个真正智能的决策大脑? 这场由DeepSeek和通义领衔的大模型之争,正在重塑中国AI产业的竞争格局。本文将为你揭开两大技术巨头的终极对决! 一、颠覆认知的技术突破 1.1 改变游戏…

3. 轴指令(omron 机器自动化控制器)——>MC_SetOverride

机器自动化控制器——第三章 轴指令 12 MC_SetOverride变量▶输入变量▶输出变量▶输入输出变量 功能说明▶时序图▶重启运动指令▶多重启动运动指令▶异常 MC_SetOverride 变更轴的目标速度。 指令名称FB/FUN图形表现ST表现MC_SetOverride超调值设定FBMC_SetOverride_instan…

从像素到世界:自动驾驶视觉感知的坐标变换体系

接着上一篇 如何让自动驾驶汽车“看清”世界?坐标映射与数据融合详解的概述,这一篇详细讲解自动驾驶多目视觉系统设计原理,并给出应用示例。 摘要 在自动驾驶系统中,准确的环境感知是实现路径规划与决策控制的基础。本文系统性地解析图像坐标系、像素坐标系、相机坐标系与…

附录B ISO15118-20测试命令

本章节给出ISO15118-20协议集的V2G命令&#xff0c;包含json、xml&#xff0c;并且根据exiCodec.jar编码得到exi内容&#xff0c; 读者可以参考使用&#xff0c;测试编解码库是否能正确编解码。 B.1 supportedAppProtocolReq json: {"supportedAppProtocolReq": {…

VLAN章节学习

为什么会有vlan这个技术&#xff1f; 1.通过划分广播域来降低广播风暴导致的设备性能下降&#xff1b; 2.提高网络管理的灵活性和通过隔离网络带来的安全性&#xff1b; 3.在成本不变的情况下增加更多的功能性&#xff1b; VLAN又称虚拟局域网&#xff08;再此扩展&#xf…

FPGA时钟约束

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、Create_clock 前言 时钟周期约束&#xff0c;就是对时钟进行约束。 一、Create_clock create_clock -name <name> -period <period> -waveform …

机房布局和布线的最佳实践:如何打造高效、安全的机房环境

机房布局和布线的最佳实践:如何打造高效、安全的机房环境 大家好,我是Echo_Wish。今天我们来聊聊机房布局和布线的问题,这可是数据中心和IT运维中的一个非常重要的环节。不管是刚刚接触运维的新人,还是已经摸爬滚打多年的老兵,都应该对机房的布局和布线有一个清晰的认识。…

spring-security原理与应用系列:建造者

目录 1.构建过程 AbstractSecurityBuilder AbstractConfiguredSecurityBuilder WebSecurity 2.建造者类图 SecurityBuilder ​​​​​​​AbstractSecurityBuilder ​​​​​​​AbstractConfiguredSecurityBuilder ​​​​​​​WebSecurity 3.小结 紧接上一篇文…

OpenHarmony子系统开发 - 电池管理(二)

OpenHarmony子系统开发 - 电池管理&#xff08;二&#xff09; 五、充电限流限压定制开发指导 概述 简介 OpenHarmony默认提供了充电限流限压的特性。在对终端设备进行充电时&#xff0c;由于环境影响&#xff0c;可能会导致电池温度过高&#xff0c;因此需要对充电电流或电…