Ответ не достигает сокета на многоадресной рассылке в Windows - PullRequest
0 голосов
/ 28 мая 2019

Я пытаюсь запустить небольшой клиент / сервер SSDP.Пока что сервер работает просто отлично, отвечая на мой M-SEARCH (согласно wireshark).Код клиента написан в Visual Studio с использованием Winsock2 (см. Код ниже).Проблема состоит в том, что ответ никогда не достигает моего вызова recv, когда я отправляю поиск по адресу многоадресной рассылки.

Я уже пытался отправлять и получать напрямую по ip-адресу сервера, который генерирует ответ, который достигает моего вызова recvправильно.Однако, когда я изменяю IP на адрес многоадресной рассылки, он не работает (хотя я вижу ответ на Wireshark!).Поэтому по какой-то причине сокет (на уровне ОС?) Отказывается передавать его приложению.

Следует отметить, что ответ всегда одноадресный.

Вот мой код:

#include <Winsock2.h> // before Windows.h, else Winsock 1 conflict
#include <Ws2tcpip.h> // needed for ip_mreq definition for multicast
#include <Windows.h>

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#define SERVERPORT 1900
char buff[] = "M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: ssdp:discover\r\nST: ssdp:all\r\n\r\n";

int main()
{
    char rcvdbuff[1000];
    int len, Ret = 2;

    WSADATA wsaData;
    if (WSAStartup(0x0101, &wsaData)) {
        perror("WSAStartup");
        return 1;
    }

    struct sockaddr_in their_addr;
    SOCKET sock;

    sock = socket(AF_INET, SOCK_DGRAM, 0);

    their_addr.sin_family = AF_INET;
    ////THIS APPROACH DOES NOT WORK
    their_addr.sin_addr.s_addr = inet_addr("239.255.255.250");
    //THIS APPROACH WORKS - SOMEHOW THE SOCKET IS BOUND TO THIS IP AND CAN THUS RECEIVE
    //their_addr.sin_addr.s_addr = inet_addr("192.168.3.90");
    their_addr.sin_port = htons(SERVERPORT);
    len = sizeof(struct sockaddr_in);

    while (1)
    {
        printf("buff:\n%s\n", buff);
        Ret = sendto(sock, buff, strlen(buff), 0, (struct sockaddr*)&their_addr, len);
        if (Ret < 0)
        {
            printf("error in SENDTO() function");
            closesocket(sock);
            return 0;
        }

        //Receiving Text from server
        printf("\n\nwaiting to recv:\n");
        memset(rcvdbuff, 0, sizeof(rcvdbuff));
        Ret = recvfrom(sock, rcvdbuff, sizeof(rcvdbuff), 0, (struct sockaddr *)&their_addr, &len);
        if (Ret < 0)
        {
            printf("Error in Receiving");
            return 0;
        }
        rcvdbuff[Ret - 1] = '\0';
        printf("RECEIVED MESSAGE FROM SERVER\t: %s\n", rcvdbuff);

        //Delay for testing purpose
        Sleep(3 * 1000);
    }
    closesocket(sock);
    WSACleanup();
}

Я попробовал одну интересную вещь (без перезапуска приложения!):

1) Сначала отправьте на прямой IP-адрес (192.168.3.90)

2) Получите ответ

3) Теперь отправьте на адрес многоадресной рассылки

4)Теперь ответ возвращается просто отлично!

Как будто сокет как-то "знает" адрес одноадресной рассылки при первом вызове send / recv.

Кто-нибудь знает, что делать или как отлаживать

1 Ответ

1 голос
/ 28 мая 2019

Я думаю Я нашел решение вопроса: брандмауэр Windows. Вот цитата из Quora :

Разрешены только те соединения, которые явно разрешены с использованием правил брандмауэра. Брандмауэр Windows по умолчанию разрешает все исходящие соединения и разрешает только установленные входящие соединения (то есть входящее соединение, которое является прямым ответом на исходящее соединение, инициированное с вашего компьютера или сети).

Именно так и происходит: мы не установили исходящее соединение, и поэтому оно заблокировано брандмауэром Windows!

В другом случае, когда я впервые отправляю напрямую, брандмауэр Windows открывается для этого точного входящего соединения, и поэтому последующая многоадресная отправка получает ответ.

...