2011-05-18 80 views
1

我想在C++中实现UpNP,我在谷歌上找到了一些源,但都没有工作。我发现这一个工作(http://www.codeproject.com/KB/IP/upnplib.aspx),但它是为.NET,所以我决定嗅探网络,看看代码在做什么,然后对套接字做同样的事情。套接字传输数据,但不能收到回应

下面是结果(全尺寸:http://i.stack.imgur.com/eLoHK.jpg): enter image description here

这表明我的包不看坏,一切似乎是相同的,一切,但我的代码源地址 ,我不知道如何控制(我的代码和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和字符串错误(WSAGetLastError())打印“未知错误”。

我希望有人能指引我走向正确的方向,我已经是最后两天尝试做这项工作了。

+0

恕我直言,你不应该改变的问题这么厉害:你可以得到你要寻找的IP地址的方式创建一个新的问题,但现在,标题是误导你得到了一个原始问题的答案... – rlc 2011-05-19 00:22:14

回答

1

编辑:

正如hasturkun指出,我最初的答案是错误的。此外,slemdx正确诊断问题:uPnP请求从错误的接口发出。问题是,我不知道如何确定正确的界面。一种可能是使用包含路由表上默认网关的接口,但我不认为这是正确的选择。可能有uPnP设备挂钩到其他接口。

一种选择是在所有可用接口上发送初始搜索数据包。也许this question的答案可以提供帮助。最后一个答案还有另外一个链接,你应该检查一下。

+0

我试着将recvfrom替换为recv并且没有任何更改,我怀疑我的问题是第一个“M-SEARCH”数据包的源地址,如图所示在finder.net.exe(工作的软件)上使用的源地址使用192.168.1.103,这与我的代码(192.168.1.1)中使用的不同,但我不知道如何设置该地址(没有使用更复杂的代码我还不明白)。 – slemdx 2011-05-18 22:22:43

+0

显示数据包跟踪的图像表明响应数据包根本不会回来(假设跟踪完成)。但无论如何,因为它似乎是一个有效的点给我。 – 2011-05-18 22:47:11

+0

-1,'recvfrom'返回源地址,否则它相当于一个普通的'recv' – Hasturkun 2011-05-18 23:03:34

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))