我正在尝试用C ++实现UpNP,我在google上找到了一些来源,但都没有。我发现这个工作(http://www.codeproject.com/KB/IP/upnplib.aspx)但它适用于.NET,所以我决定嗅探网络以查看代码正在做什么,然后对套接字执行相同的操作。
以下是结果(完整尺寸:http://i.stack.imgur.com/eLoHK.jpg):
这告诉我数据包看起来并不坏,一切似乎都是一样的,除了我的代码的源地址,我不知道如何控制(我的两个)代码和finder.net.exe正在连接到同一网络的同一台计算机上进行测试。)
这是我的代码:
#define upnp_broadcast_ip "239.255.255.250"
#define upnp_broadcast_port 1900
#define upnp_search_request "M-SEARCH * HTTP/1.1\r\n" \
"Host:239.255.255.250:1900\r\n" \
"ST:upnp:rootdevice\r\n" \
"Man:\"ssdp:discover\"\r\n" \
"MX:3\r\n" \
"\r\n"
WSAStartup(MAKEWORD(2, 2), &WsaData);
BOOL discover( )
{
SOCKET ConnectSocket;
struct sockaddr_in Addr;
char Buffer[1450];
int t = 0,
iResult = 0,
TrueLen = sizeof(bool);
bool True = true;
ulong One = 1;
// Open datagram socket
ConnectSocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
// Clear out struct
memset( &Addr, 0, sizeof(Addr) );
// Specify the address family, IP address, and port
Addr.sin_family = AF_INET;
Addr.sin_port = htons( upnp_broadcast_port );
Addr.sin_addr.s_addr = inet_addr( upnp_broadcast_ip );
iResult = setsockopt( ConnectSocket, SOL_SOCKET, SO_BROADCAST, (char*)&True, TrueLen ); // Not sure what is this for
// Transmit data
int sent = sendto( ConnectSocket, upnp_search_request, strlen(upnp_search_request), 0, (struct sockaddr*)&Addr, sizeof(Addr) );
// Try to receive data 10 times
for( t = 0; t < 10; t++ )
{
ioctlsocket( ConnectSocket, FIONBIO, &One );
// Clear out buffer
memset( &Buffer, 0, sizeof(Buffer) );
int length = sizeof(Addr);
// Receive data
iResult = recvfrom( ConnectSocket, Buffer, (sizeof(Buffer) - 1), 0, (struct sockaddr*)&Addr, &length );
if( iResult == SOCKET_ERROR)
{
Sleep( 1000 );
continue;
} else {
// Do stuff with received data
}
}
closesocket( ConnectSocket );
return FALSE;
}
我删除了所有WSAGetLastError()错误检查以使代码更容易阅读,一切正常,直到recvfrom,总是返回-1并且strerror(WSAGetLastError())打印“未知错误”。
我希望有人可以指导我朝着正确的方向前进,我已经是最近两天试图完成这项工作了。
答案 0 :(得分:2)
为何播出? UPnP使用多播,所以我记得(Unix)你应该使用setsockopt()来请求内核加入一个多播组。我不确定Windows,它可能是同一个电话。 类似的东西:
struct ip_mreq mreq;
....
mreq.imr_multiaddr.s_addr=inet_addr(GROUP_IP);
mreq.imr_interface.s_addr=htonl(INADDR_ANY);
setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq))
答案 1 :(得分:1)
编辑:
正如hasturkun指出的那样,我最初的回答是错误的。此外,slemdx正确诊断出问题:uPnP请求是从错误的接口发出的。问题是,我不确定如何确定正确的界面。一种可能性是在路由表上使用包含默认网关的接口,但我认为这不是正确的选择。可能有uPnP设备挂钩到其他接口。
一种选择是在所有可用接口上发送初始搜索数据包。也许this question的答案可以提供帮助。最后一个答案还有另一个链接,你应该检查。