2011-05-18 79 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))