如何用C++结合UDP实现跨互联网的设备间消息传输?
跨互联网UDP单消息传输实现方案
问题根源
跨网通信失败的核心原因是NAT穿透问题:服务端所在网络的路由器会拦截外部发往公网IP的UDP包,因为它不知道要把包转发给局域网内的服务端设备。
关键解决步骤
1. 配置路由器端口转发
这是最直接的方案,适合已知双方设备的场景:
- 登录服务端所在网络的路由器管理后台(通常为
192.168.1.1或192.168.0.1) - 找到端口转发/虚拟服务器设置项
- 添加规则:将外部UDP端口
54000(与代码中端口一致)转发到服务端的局域网IP(如192.168.1.100)和端口54000 - 保存设置
2. 放行防火墙端口
- 服务端的Windows防火墙需允许UDP端口
54000的入站连接 - 若路由器自带防火墙,也要确保UDP
54000端口的入站流量被允许
3. 客户端代码调整
仅需将IP_ADDRESS修改为服务端的公网IP即可,无需同时使用公网和局域网IP。
验证方法
- 可通过命令行工具(如
nc -u 公网IP 54000)发送测试包,确认端口是否对外开放 - 客户端发送消息时,确保服务端处于运行状态
你的现有代码(核心逻辑无需修改)
服务端代码
#include <iostream> #include <WS2tcpip.h> #pragma comment (lib, "ws2_32.lib") int main() { WSADATA wsadata; WORD version = MAKEWORD(2, 2); int wsOk = WSAStartup(version, &wsadata); if (wsOk != 0) { std::cout << "Cannot Start Winsock\n"; return -1; } SOCKET in = socket(AF_INET, SOCK_DGRAM, 0); sockaddr_in serverHint; serverHint.sin_addr.S_un.S_addr = ADDR_ANY; serverHint.sin_family = AF_INET; serverHint.sin_port = htons(54000); if (bind(in, (sockaddr*) &serverHint, sizeof(serverHint)) == SOCKET_ERROR) { std::cout << "Can't Bind Socket " << WSAGetLastError() << std::endl; return -1; } sockaddr_in client; int clientLength = sizeof(client); ZeroMemory(&client, clientLength); char buffer[1024]; while (true) { ZeroMemory(&buffer, sizeof(buffer)); int numOfBytes = recvfrom(in, buffer, sizeof(buffer), 0, (sockaddr*) &client, &clientLength); if (numOfBytes == SOCKET_ERROR) { std::cout << "Error Recieving Client Message " << WSAGetLastError() << std::endl; continue; } char clientIP[256]; ZeroMemory(clientIP, sizeof(clientIP)); inet_ntop(AF_INET, &client.sin_addr, clientIP, sizeof(clientIP)); std::cout << "Message Received From [" << clientIP << "] = " << buffer << std::endl; } closesocket(in); WSACleanup(); }
客户端代码
#include <iostream> #include <thread> #include <WS2tcpip.h> #pragma comment (lib, "ws2_32.lib") const char* IP_ADDRESS = "服务端公网IP"; // 修改此处为服务端公网IP int main() { WSADATA wsadata; WORD version = MAKEWORD(2, 2); int wsOk = WSAStartup(version, &wsadata); if (wsOk != 0) { std::cout << "Cannot Start Winsock\n"; return -1; } sockaddr_in server; server.sin_family = AF_INET; server.sin_port = htons(54000); inet_pton(AF_INET, IP_ADDRESS, &server.sin_addr); SOCKET out = socket(AF_INET, SOCK_DGRAM, 0); std::string message = "Hello!\n"; for (size_t index = 0; index < 100; index++) { int sendOk = sendto(out, message.c_str(), message.size() + 1, 0, (sockaddr*) &server, sizeof(server)); if (sendOk == SOCKET_ERROR) std::cout << "Failed To Send" << WSAGetLastError() << std::endl; } closesocket(out); WSACleanup(); return 0; }
内容的提问来源于stack exchange,提问作者Jack Koscheka
相关产品推荐
相关产品推荐

