(Winsock) UDP-прием работает, но отправка завершается неудачно для того же сокета - PullRequest
0 голосов
/ 09 февраля 2020

У меня проблемы с работой сокета UDP в Windows. У меня есть отдельное приложение, которое я пытаюсь связать с этими выходами через порт 1625 и получать через порт 26027. Я попытался создать простой исполняемый файл, который читает одно сообщение и отправляет одно сообщение. Чтение работает нормально, но отправка завершается с ошибкой WSAEADDRNOTAVAIL (10049).

Для устранения неполадок я также пробовал эквивалентный код в Linux с (используя подсистему Windows для Linux) на та же машина и работает отлично. Так что я не могу понять, в чем проблема. Я также попытался отключить Windows Firewall, но это не имело значения. Будем благодарны за любые предложения.

Код Windows Visual 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] = '\0';
    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] = '\0';
    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

Я также могу проверить, что вывод на порт 26027 через эту Linux реализацию, полученную другим приложением, и ее также можно увидеть в Wireshark.

РЕДАКТИРОВАТЬ:
После ответа Реми ниже я смог получить эту работу в соответствии с комментариями ниже. Чтобы уточнить мою сеть:

Моя сеть, если я просматриваю ее с помощью Wireshark, теперь выглядит следующим образом:

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

Где мой узел привязывается к 1625, где он может recv() UDP с какого-то неизвестного номера порта (50223 в данном случае) и sendto() порт 26027.

1 Ответ

3 голосов
/ 09 февраля 2020

Вы не можете использовать recv() с сокетом UDP, если сначала не позвоните connect(), чтобы статически назначить IP / порт однорангового устройства сокету, чего вы не делаете. Так что recv() потерпит неудачу, но вы не проверяете это. Вместо этого вам нужно использовать recvfrom().

Кроме того, несмотря ни на что, вы не можете отправлять пакеты на INADDR_ANY (0.0.0.0), как есть. Вот почему вы получаете ошибку отправки.

Функция отправки

WSAEADDRNOTAVAIL

Удаленный адрес не является действительным адресом, например, ADDR_ANY .

Windows Коды ошибок сокетов

WSAEADDRNOTAVAIL
10049

Невозможно назначить запрошенный адрес. Запрошенный адрес недопустим в его контексте . Обычно это происходит в результате попытки привязки к адресу, который недопустим для локального компьютера. Это также может быть результатом подключения, sendto, WSAConnect, WSAJoinLeaf или WSASendTo, когда удаленный адрес или порт недопустим для удаленного компьютера (например, адрес или порт 0) .

Вам необходимо отправить на фактический IP / порт, например, на IP / порт партнера, который сообщается recvfrom() при получении пакета.

...