(Winsock) UDP 接收工作但发送失败相同的套接字

(Winsock) UDP receive works but send fails for same socket

我在 Windows 中使用 UDP 套接字时遇到问题。我有一个单独的应用程序,我试图与端口 1625 上的输出通信并在端口 26027 上接收。我试图制作一个简单的可执行文件来读取一条消息并发送一条消息。读取工作正常,但发送以 WSAEADDRNOTAVAIL (10049) 错误结束。

为了解决问题,我还在同一台机器上尝试了 Linux 中的等效代码(使用 Windows 子系统 Linux),它工作正常。所以我无法弄清楚问题是什么。我也尝试禁用 Windows 防火墙,但这并没有什么不同。如有任何建议,我们将不胜感激。

WindowsVisual C++代码:

#pragma comment(lib, "Ws2_32.lib")

#include <iostream>
#include <WS2tcpip.h>

#define MAXLINE 1024

int main()
{
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);

    // Define local port address.
    sockaddr_in local_port;
    memset(&local_port, 0, sizeof(local_port));
    local_port.sin_family = AF_INET;
    local_port.sin_addr.s_addr = INADDR_ANY;
    local_port.sin_port = htons(1625);

    // Bind local socket.
    int socket_id = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    bind(socket_id, (const struct sockaddr *)&local_port, sizeof(local_port));

    // Receive UDP Port message.
    char in_buffer[MAXLINE];
    int num_bytes = recv(socket_id, (char *)in_buffer, MAXLINE, 0);
    in_buffer[num_bytes] = '[=10=]';
    printf("Received : %s\n", in_buffer);

    // Set up send destination port.
    sockaddr_in dest_port;
    memset(&dest_port, 0, sizeof(dest_port));
    dest_port.sin_family = AF_INET;
    dest_port.sin_addr.s_addr = INADDR_ANY;
    dest_port.sin_port = htons(26027);

    // Send UDP message to specific UDP port.
    char out_buffer[] = "Test message";
    int result = sendto(
        socket_id, out_buffer, strlen(out_buffer), 0, (struct sockaddr *)&dest_port, sizeof(dest_port));
    printf("Send result : %d -- WSA Error : %d\n", result, WSAGetLastError());

    closesocket(socket_id);
    return 0;
}

此可执行文件 运行 的终端输出是:

Received : 5e4009df*755=-0.0028:761=0.6942

Send result : -1 -- WSA Error : 10049

WSL linux C++ 代码(相同的源代码,除了 WSA 包含和错误输出):

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define MAXLINE 1024

int main()
{
    // Define local port address.
    sockaddr_in local_port;
    memset(&local_port, 0, sizeof(local_port));
    local_port.sin_family = AF_INET;
    local_port.sin_addr.s_addr = INADDR_ANY;
    local_port.sin_port = htons(1625);

    // Bind local socket.
    int socket_id = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    bind(socket_id, (const struct sockaddr *)&local_port, sizeof(local_port));

    // Receive UDP Port message.
    char in_buffer[MAXLINE];
    int num_bytes = recv(socket_id, (char *)in_buffer, MAXLINE, 0);
    in_buffer[num_bytes] = '[=12=]';
    printf("Received : %s\n", in_buffer);

    // Set up send destination port.
    sockaddr_in dest_port;
    memset(&dest_port, 0, sizeof(dest_port));
    dest_port.sin_family = AF_INET;
    dest_port.sin_addr.s_addr = INADDR_ANY;
    dest_port.sin_port = htons(26027);

    // Send UDP message to specific UDP port.
    char out_buffer[] = "Test message";
    int result = sendto(
        socket_id, out_buffer, strlen(out_buffer), 0, (struct sockaddr *) &dest_port, sizeof(dest_port));
    printf("Send result : %d\n", result);

    close(socket_id);
    return 0;
}

此可执行文件 运行 的终端输出是:

Received : 5e4009df*755=-0.0028:761=0.6942

Send result : 12

我还可以验证通过此 Linux 实现到端口 26027 的输出是否已被其他应用程序接收,并且也可以在 Wireshark 中看到它。

编辑:
在雷米在下面回答之后,我能够按照下面的评论进行这项工作。澄清我的网络:

如果我使用 Wireshark 查看它,我的网络现在看起来像:

127.0.0.1   UDP 50223 → 1625 Len=32  
127.0.0.1   UDP 1625 → 26027 Len=12  

我的节点绑定到 1625,它可以从某个未知端口号(在本例中为 50223)和 sendto() 端口 26027 recv() UDP。

您不能将 recv() 与 UDP 套接字一起使用,除非您首先调用 connect() 将对等方的 IP/port 静态分配给套接字,而您并没有这样做。所以 recv() 会失败,但你没有检查它。您需要改用 recvfrom()

此外,无论如何,您都不能像现在这样向INADDR_ANY (0.0.0.0) 发送数据包。这就是您收到发送错误的原因。

sendto Function

WSAEADDRNOTAVAIL

The remote address is not a valid address, for example, ADDR_ANY.

Windows Sockets Error Codes

WSAEADDRNOTAVAIL
10049

Cannot assign requested address. The requested address is not valid in its context. This normally results from an attempt to bind to an address that is not valid for the local computer. This can also result from connect, sendto, WSAConnect, WSAJoinLeaf, or WSASendTo when the remote address or port is not valid for a remote computer (for example, address or port 0).

您需要发送到一个实际的 IP/port,例如 recvfrom() 在收到数据包时报告的对等 IP/port。