【问题标题】:Response doesn't reach socket on multicast in Windows响应未到达 Windows 中的多播套接字
【发布时间】:2019-05-28 13:41:50
【问题描述】:

我正在尝试启动并运行一个小型 SSDP 客户端/服务器。到目前为止,服务器运行良好,响应了我的 M-SEARCH(根据 wireshark)。客户端代码是使用 Winsock2 在 Visual Studio 中编写的(请参见下面的代码)。问题是当我将搜索发送到多播地址时,响应永远不会到达我的 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) 现在响应恢复正常!

就好像套接字以某种方式从第一次发送/接收调用中“知道”了单播地址。

有人知道要做什么或如何调试吗?

【问题讨论】:

  • 我的猜测是,这与您在 sendtorecvfrom 调用中使用 their_addrlen 有关。您是否尝试对不同的调用使用不同的变量(包括套接字地址结构和结构长度)?您是否尝试过在调试器中单步执行代码以准确查看代码何时开始失败?此外,当sendtorecvfrom 失败时,您应该打印errno 的值以了解为什么失败。
  • 嗯,当我使用此设置直接发送到 192.168.3.90 时,它确实工作得很好。当我发送到多播地址时,recvfrom 永远不会失败,它只是没有收到任何数据(即使我可以在 Wireshark 中看到响应!),所以确实没有要检查的错误代码。我认为操作系统不会以某种方式将数据报传递给应用程序。
  • 我怀疑我在这里遗漏了一些东西,但是......如果你想接收 IP 多播数据包,那么你需要加入有问题的多播组。类似setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, ...).
  • 它不是多播数据包,因为响应是单播的(来自​​ 192.168.3.90 -> “我的 IP 地址”)

标签: c++ udp multicast winsock2 ssdp


【解决方案1】:

认为我找到了问题的解决方案:Windows 防火墙。 这是来自 Quora 的引述:

仅允许使用防火墙规则明确允许的连接。默认情况下,Windows 防火墙允许所有出站连接,并且只允许已建立的入站连接(即直接响应从您的计算机或网络发起的出站连接的入站连接)。

正是这种情况:我们没有建立出站连接,因此它被 Windows 防火墙阻止了!

在另一种情况下,当我第一次直接发送时,Windows 防火墙会为该确切的入站连接打开,因此随后的多播发送会得到响应。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-09
    • 2017-09-09
    • 1970-01-01
    • 1970-01-01
    • 2014-12-16
    • 2013-03-31
    相关资源
    最近更新 更多