2016-09-19 178 views
1

我該如何去尋找C++中用戶的外部IP?我需要一種適用於任何系統的方法,而不僅僅是我的方法。此外,該系統可能位於路由器後面,因此NAT將發揮作用,使得難以檢索外部IP。如何在C++中獲取外部IP地址?

理想情況下,我想這樣做,而不使用任何第三方服務,如whatsmyip。但是,我不確定這是否可能。如果我不使用第三方服務,我必須通過路由器,如果ping被禁用,我猜這可能是不可能的(我可能是錯的,不太確定)。

如果我要使用像whatsmyip這樣的第三方服務,我該如何解決這個問題?是否有他們暴露的Web服務?我已經看到這個鏈接:http://automation.whatismyip.com/n09230945.asp但它似乎並沒有工作。 是否有可能通過使用某些HTTP方法獲取外部IP並檢索它,或者我是否需要刮取頁面以從中獲取IP?

我僅限於使用Windows API來實現這一點(沒有第三方的API)

+2

你不知道。我的意思是你沒有使用C++獲取接口的IP地址(* any * interface),因爲C++沒有任何類型的網絡概念。而是使用本機平臺特定的功能來獲取接口列表。如果你搜索一下,你會在互聯網上找到很多關於如何做到這一點的例子,包括很多在這個網站上,嘗試搜索例如*枚舉網絡接口窗口api * –

+0

@JoachimPileborg - 我知道如何枚舉網絡接口。但是,我特別需要使用C++編程方式查找外部IP。我希望有本地API可以幫助我完成這一點。 – spdcbr

+0

你是指你的電腦「外部」地址,還是路由器?你可以很容易地找出一個,但不是其他的。可以使用http://www.whatsmyip.org/之類的東西,也可以直接查找路由器。如果您不想使用第三方http請求庫,請查看[Windows Internet函數](https://msdn.microsoft.com/en-us/library/windows/desktop/aa383630(v = vs.85)的.aspx)。 –

回答

1

這有什麼做與C++或任何特別的語言。
此外,知道你的路由器的地址不會對你有什麼好處,你會知道它是NAT地址,而不是外部地址,也可能你的路由器不是通往互聯網的最後一個路由器。
您必須使用外部實體 - 通常是某種可以報告與之聯繫的路由器的IP地址的Web服務。
以下是有人詢問如何在PHP中獲取客戶端IP地址的sample question

+0

我不同意。他的問題是一個可以解決的問題,只要你願意使用HTTP GET(任何其他網站會告訴你你是外部IP地址)。你如何做到這一點在Windows C++是不同的,然後C#或Python。所以我認爲它對Windows C++特有的問題和答案很有幫助。感謝Software_Designer提供了一個可行的答案。 –

0

您可以使用類似curl或curlpp的庫來獲取http://myexternalip.com/raw的內容。它的迴應只是你的外部IP,你可以閱讀和使用它。

+0

這是第三方圖書館,我猜。有沒有我可以完成同樣的事情的窗口庫? – spdcbr

+0

如果您使用的是Unix,我建議您使用exec並執行「wget http://myexternalip.com/raw」命令將內容下載爲html,然後閱讀該文件。我不知道是否有命令在Windows下載html內容。如果有的話,你可以從你的應用程序執行它,然後讀取下載的html文件。 –

1

enter image description here

這裏是winsock的方式。它只是提取嵌入在服務器發送的HTML代碼中的IP地址。

此代碼使用http://api.ipify.org/

下面是兩個不同的代碼。一個用於VS2012-2015,使用strcpy_s(),另一個用於使用strcpy()的Visual C++ 6.0,因爲VS2012-2015會拋出錯誤消息,提示您使用strcpy_s()而不是strcpy()

Visual Studio 2012-2015的代碼。

#include "stdafx.h" 
#include <string.h> 
#include <winsock2.h> 
#include <windows.h> 
#include <iostream> 
#include <vector> 
#include <locale> 
#include <sstream> 
using namespace std; 
#pragma comment(lib,"ws2_32.lib") 


string website_HTML; 
locale local; 
void get_Website(string url); 
char lineBuffer[200][80] = { ' ' }; 
char buffer[10000]; 
char ip_address[16]; 
int i = 0, bufLen = 0, j = 0, lineCount = 0; 
int lineIndex = 0, posIndex = 0; 

//**************************************************** 

int main(void){ 
    cout << "\n\n\n"; 
    get_Website("api.ipify.org"); 
    for (size_t i = 0; i<website_HTML.length(); ++i) website_HTML[i] = tolower(website_HTML[i], local); 

    istringstream ss(website_HTML); 
    string stoken; 

    while (getline(ss, stoken, '\n')) { 

     //cout <<"-->"<< stoken.c_str() << '\n'; 

     strcpy_s(lineBuffer[lineIndex], stoken.c_str()); 
     int dot = 0; 
     for (int ii = 0; ii< strlen(lineBuffer[lineIndex]); ii++){ 

      if (lineBuffer[lineIndex][ii] == '.') dot++; 
      if (dot >= 3){ 
       dot = 0; 
       strcpy_s(ip_address, lineBuffer[lineIndex]); 
      } 
     } 

     lineIndex++; 
    } 
    cout << "Your IP Address is " << ip_address << " \n\n"; 


    cout << "\nPress ANY key to close.\n\n"; 
    cin.ignore(); cin.get(); 

    return 0; 
} 

//**************************************************** 

void get_Website(string url){ 
    WSADATA wsaData; 
    SOCKET Socket; 
    SOCKADDR_IN SockAddr; 
    int lineCount = 0; 
    int rowCount = 0; 
    struct hostent *host; 
    string get_http; 


    get_http = "GET/HTTP/1.1\r\nHost: " + url + "\r\nConnection: close\r\n\r\n"; 

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){ 
     cout << "WSAStartup failed.\n"; 
     system("pause"); 
     //return 1; 
    } 

    Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    host = gethostbyname(url.c_str()); 

    SockAddr.sin_port = htons(80); 
    SockAddr.sin_family = AF_INET; 
    SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr); 

    if (connect(Socket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr)) != 0){ 
     cout << "Could not connect"; 
     system("pause"); 
     //return 1; 
    } 
    send(Socket, get_http.c_str(), strlen(get_http.c_str()), 0); 

    int nDataLength; 
    while ((nDataLength = recv(Socket, buffer, 10000, 0)) > 0){ 
     int i = 0; 
     while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r'){ 

      website_HTML += buffer[i]; 
      i += 1; 
     } 
    } 

    closesocket(Socket); 
    WSACleanup(); 

} 

的Visual C++ 6.0代碼

#include <string.h> 
    #include <winsock2.h> 
    #include <windows.h> 
    #include <iostream> 
    #include <vector> 
    #include <locale> 
    #include <sstream> 
    using namespace std; 
    #pragma comment(lib,"ws2_32.lib") 


    string website_HTML; 
    locale local; 
    void get_Website(string url); 
    char lineBuffer[200][80] ={' '}; 
    char buffer[10000]; 
    char ip_address[16]; 
    int i = 0, bufLen=0, j=0,lineCount=0; 
    int lineIndex=0, posIndex=0; 

    //**************************************************** 

    int main(void){ 
     cout << "\n\n\n"; 
     get_Website("api.ipify.org"); 
     for (size_t i=0; i<website_HTML.length(); ++i) website_HTML[i]= tolower(website_HTML[i],local); 

     istringstream ss(website_HTML); 
     string stoken; 

     while(getline(ss, stoken, '\n')) { 

        strcpy(lineBuffer[lineIndex],stoken.c_str()); 
        int dot=0; 
        for (int ii=0; ii< strlen(lineBuffer[lineIndex]); ii++){ 

         if (lineBuffer[lineIndex][ii] == '.') dot++; 
         if (dot>=3){ 
          dot=0; 
          strcpy(ip_address,lineBuffer[lineIndex]); 
         } 
        } 
        lineIndex++; 
     } 
     cout<<"Your IP Address is "<< ip_address<<" \n\n"; 

     cout<<"\nPress ANY key to close.\n\n"; 
     cin.ignore(); cin.get(); 


    return 0; 
} 

//**************************************************** 

void get_Website(string url){ 
    WSADATA wsaData; 
    SOCKET Socket; 
    SOCKADDR_IN SockAddr; 
    int lineCount=0; 
    int rowCount=0; 
    struct hostent *host; 
    string get_http; 


    get_http = "GET/HTTP/1.1\r\nHost: " + url + "\r\nConnection: close\r\n\r\n"; 

    if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0){ 
     cout << "WSAStartup failed.\n"; 
     system("pause"); 
     //return 1; 
    } 

    Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 
    host = gethostbyname(url.c_str()); 

    SockAddr.sin_port=htons(80); 
    SockAddr.sin_family=AF_INET; 
    SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr); 

    if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr)) != 0){ 
     cout << "Could not connect"; 
     system("pause"); 
     //return 1; 
    } 
    send(Socket,get_http.c_str(), strlen(get_http.c_str()),0); 

    int nDataLength; 
    while ((nDataLength = recv(Socket,buffer,10000,0)) > 0){   
     int i = 0; 
     while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r'){ 

      website_HTML+=buffer[i]; 
      i += 1; 
     }    
    } 

    closesocket(Socket); 
    WSACleanup(); 

} 
1

在理論上,你可以使用Windows的UPnP API來做到這一點。您首先要使用UPnPDeviceFinder來枚舉Internet網關設備。然後你會得到一個IUPnPRemoteEndpointInfo爲網關(當然,還有通常只有一個,反正),並調用它GetStringValue,使含"RemoteAddress"一個字符串來得到它的遠程地址(我認爲意味着它的外部地址,但我會承認我不完全確定)。哦,因爲這是COM,那必須是一個系統字符串,而不是一個普通的字符串。

從外部提供商獲取IP是lot更容易。不使用任何3個黨庫,它的代碼如下所示:

#include <windows.h> 
#include <wininet.h> 
#include <string> 
#include <iostream> 

std::string real_ip() { 

    HINTERNET net = InternetOpen("IP retriever", 
     INTERNET_OPEN_TYPE_PRECONFIG, 
     NULL, 
     NULL, 
     0); 

    HINTERNET conn = InternetOpenUrl(net, 
            "http://myexternalip.com/raw", 
             NULL, 
             0, 
             INTERNET_FLAG_RELOAD, 
             0); 

    char buffer[4096]; 
    DWORD read; 

    InternetReadFile(conn, buffer, sizeof(buffer)/sizeof(buffer[0]), &read); 
    InternetCloseHandle(net);  

    return std::string(buffer, read); 
} 

int main() { 
    std::cout << real_ip() << "\n"; 
} 

編譯:

cl ip_addr.cpp wininet.lib 

注意:如果您的機器配置爲使用IPv6,這樣可以(並且將)檢索你的IPv6地址)。