You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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的入站连接
  • 若路由器自带防火墙,也要确保UDP54000端口的入站流量被允许

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 10:05:23