欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 新车 > 【C++网络编程】第5篇:UDP与广播通信

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

2025/4/2 2:15:31 来源:https://blog.csdn.net/JuicyActiveGilbert/article/details/146468143  浏览:    关键词:【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. 测试结果

在这里插入图片描述


版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词