首页 文章

客户端getsocketname()和server recv()上的UDP源端口不同

提问于
浏览
0

嗨我的问题很简单:

我尝试通过TCP连接 Build UDP连接(因为多个客户端通过多个通道连接到服务器,我想通过主TCP连接识别相同的客户端)

我通过在客户端上创建TCP和UDP套接字并将OS通过TCP随机分配的本地UDP端口传输到服务器来完成此操作 . (在Windows上,我通过getsocketname()获取sendto()之后的端口 . 在服务器上,我使用此端口将UDP数据包发送到此确切的客户端 . 不幸的是,我真正要发送到的端口与我发送到服务器的本地端口不同 .

例如:

我的客户端获得分配的本地UDP端口56423 . 通过已 Build 的TCP连接将其发送到我的服务器 . 服务器尝试将UDP数据包发送到该端口 - >失败 . 当我使用标准方式通过UDP套接字上的recv()检索服务器上的端口时,它报告源端口为30299.(我必须提前发送UDP数据包以获取该信息,但我想避免实现UDP连接握手)

怎么会这样?

据我所知,UDP只有一个目的端口和一个源端口 . 所以它应该通过将客户端本地端口发送到服务器来工作 . 中间是否可能存在使用备用端口的代理服务?

编辑:一些代码:

在客户端:(s32 = int,c8 = char)

if(m_WinSock == INVALID_SOCKET)
    return;

struct sockaddr_storage addr;
s32 len = sizeof(sockaddr);

getsockname(m_WinSock, (SOCKADDR*)&addr, &len);
c8 ipstr[INET6_ADDRSTRLEN + 1];
s32 port;
if(addr.ss_family == AF_INET)
{
    struct sockaddr_in *s = (struct sockaddr_in *)&addr;
    m_uLocalPort = ntohs(s->sin_port);
    inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
}
else
{ // AF_INET6
    struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
    m_uLocalPort = ntohs(s->sin6_port);
    inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
}

之后,m_uLocalPort通过TCP传输 .

在服务器上:

SOCKADDR_IN address;
    ZeroMemory(&address, sizeof(address));
    address.sin_addr = addrin;
    address.sin_port = htons((u16)remoteport);
    address.sin_family = AF_INET;

remoteport是客户端发送的端口 .

从客户端发送数据包后在服务器上使用此代码:

struct sockaddr_storage addr;
s32 len = sizeof(sockaddr);
s32 bytes = recvfrom(m_WinSock, m_RecvBuffer, NET_MAX_UDP_SIZE, 0, (SOCKADDR*)&addr, &len);
m_RecvAddress = *(struct sockaddr_in *)&addr;

s32 port = ntohs(m_RecvAddress.sin_port);
printf("recv from port %i\n", port);

我收到一个完全不同的端口 .

1 回答

  • 2

    这不是解决问题的可靠方法 . 例如,NAT可以阻碍并重新映射您的端口甚至是从客户端看到的本地IP . 您可能还需要进行udp打孔 .

    正确的方法是不假设tcp和udp有任何关联 - 它们是不同的管道 .

    编辑:例如:

    • 客户端 connect() 到服务器的公共tcp接口 .

    • 身份验证

    • Server向客户端发送身份验证代码(cookie) .

    • 客户端 sendto() 服务器的公共udp接口,带有cookie .

    • 服务器从 recvfrom() 获取 sockaddr .

    • 服务器使用cookie将这种 sockaddr 连接到revalent tcp连接 . 可选择检查/限制ip以防止其他人的公牛力量 .

    • 也就是说,现在你有一对连接 - 一个接受的tcp套接字和 sockaddr 用于udp通信 .

    PS . 您可能还想对握手进行一些加密,但这不是问题的范围 .

相关问题