Windows 中的多播响应未到达套接字
Response doesn't reach socket on multicast in Windows
我正在尝试启动一个小的 SSDP 客户端/服务器 运行。到目前为止,服务器工作正常,响应我的 M-SEARCH(根据 wireshark)。客户端代码是使用 Winsock2 在 Visual Studio 中编写的(请参见下面的代码)。问题是当我将搜索发送到多播地址时,响应永远不会到达我的 recv 调用。
我已经尝试过直接向服务器 ip 地址发送和接收,这将生成一个正确到达我的 recv 调用的响应。但是,当我将 ip 更改为多播地址时,它不起作用(即使我可以在 Wireshark 上看到响应!)。因此,出于某种原因,套接字(在 OS 级别?)拒绝将其传递给应用程序。
我应该注意到响应总是单播的。
这是我的代码:
#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] = '[=11=]';
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) 现在回复正常了!
就好像套接字不知何故 'knows' 来自第一个 send/recv 调用的单播地址。
有谁知道该做什么或如何调试?
我 认为 我找到了问题的解决方案:Windows 防火墙。
这是来自 Quora 的引述:
只允许使用防火墙规则明确允许的连接。 Windows 默认情况下,防火墙允许所有出站连接,并且仅允许已建立的入站连接(即直接响应从您的计算机或网络发起的出站连接的入站连接)。
情况确实如此:我们还没有建立出站连接,因此被Windows 防火墙阻止了!
在另一种情况下,当我第一次直接发送时,Windows 防火墙会为那个确切的入站连接打开,因此后续的多播发送会得到响应。
我正在尝试启动一个小的 SSDP 客户端/服务器 运行。到目前为止,服务器工作正常,响应我的 M-SEARCH(根据 wireshark)。客户端代码是使用 Winsock2 在 Visual Studio 中编写的(请参见下面的代码)。问题是当我将搜索发送到多播地址时,响应永远不会到达我的 recv 调用。
我已经尝试过直接向服务器 ip 地址发送和接收,这将生成一个正确到达我的 recv 调用的响应。但是,当我将 ip 更改为多播地址时,它不起作用(即使我可以在 Wireshark 上看到响应!)。因此,出于某种原因,套接字(在 OS 级别?)拒绝将其传递给应用程序。
我应该注意到响应总是单播的。
这是我的代码:
#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] = '[=11=]';
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) 现在回复正常了!
就好像套接字不知何故 'knows' 来自第一个 send/recv 调用的单播地址。
有谁知道该做什么或如何调试?
我 认为 我找到了问题的解决方案:Windows 防火墙。
这是来自 Quora 的引述:
只允许使用防火墙规则明确允许的连接。 Windows 默认情况下,防火墙允许所有出站连接,并且仅允许已建立的入站连接(即直接响应从您的计算机或网络发起的出站连接的入站连接)。
情况确实如此:我们还没有建立出站连接,因此被Windows 防火墙阻止了!
在另一种情况下,当我第一次直接发送时,Windows 防火墙会为那个确切的入站连接打开,因此后续的多播发送会得到响应。