Linux/C++:获取Internet IP地址(而不是本地计算机的IP)

4
如何以编程方式获取互联网IP地址?
1)如果计算机使用USB调制解调器直接连接到互联网。
2)如果计算机通过另一台计算机或调制解调器/路由器连接到互联网。
是否有办法同时完成这两个任务?
附注:此链接提供了确切的互联网IP地址,但我该如何在程序中使用它?

在@unbeli对我的答案的评论之后,我重新阅读了问题。虽然您可以使用像您链接中的网站和响应中的网站那样的网站,但如果计算机位于代理服务器或NAT防火墙后面,则答案将是代理或防火墙的地址,而不是发出请求的计算机的地址。 - Matt McClellan
7个回答

4

我必须使用libcurl吗?我不能使用套接字吗? - user197967
你可以这样做,但是需要付出更多的努力。如果你问我,原始套接字很麻烦。如果你严格使用Linux并处于受控环境中,你也可以通过管道传输像curl或wget这样的命令来完成。 - Krumelur
不,我使用Linux和Cygwin。但是我希望我的应用程序尽可能地独立。我不想为一个简单的任务包含整个库。 - user197967
HTTP看起来是一个简单的协议,但实际上它的实现相当复杂。我真的不建议去重复造轮子。更不用说BSD套接字本身需要相当多的支持代码了。 如果你想要除curl之外的东西,我可以建议你看看其他选择:http://curl.haxx.se/libcurl/competitors.html - Krumelur
我过去使用过libcurl,它简单易用。除非我能通过套接字找到实现我想要的功能的方法,否则我会继续使用libcurl。 - user197967

3
如果想要通过c++访问网页,请使用CurlPP。使用它下载已找到的whatismyip-page即可。

2
  1. 你可以编写套接字代码,向该链接发送http请求。

  2. 在Unix/Linux/Cygwin下,您可以使用system("wget http://www.whatismyip.com/automation/n09230945.asp");然后打开文件“n09230945.asp”并读取其内容。

以下是使用套接字进行请求的示例(我修改了一个在线示例以用于此特定目的)。注意:这只是一个示例,真正的实现需要更好地处理错误:

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

#define RCVBUFSIZE 1024

int main(int argc, char *argv[])
{
    int sock;                        // Socket descriptor
    struct sockaddr_in servAddr;     // server address
    unsigned short servPort;         // server port
    char const *servIP;              // Server IP address (dotted quad)
    char const *request;             // String to send to server
    char recvBuffer[RCVBUFSIZE];     // Buffer for response string
    unsigned int requestLen;         // Length of string to send
    int bytesRcvd;                   // Bytes read in single recv()
    bool status = true;

    // Initialize port
    servIP = "72.233.89.199";
    servPort = 80;
    request = "GET /automation/n09230945.asp HTTP/1.1\r\nHost: www.whatismyip.com\r\n\r\n";

    std::cout << request << std::endl;

    /* Create a reliable, stream socket using TCP */
    if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    {
        status = false;
    }

    if (status)
    {
        // Convert dotted decimal into binary server address.
        memset(&servAddr, 0, sizeof(servAddr));
        servAddr.sin_family      = AF_INET;
        servAddr.sin_addr.s_addr = inet_addr(servIP);
        servAddr.sin_port        = htons(servPort);

        // Connect to the server.
        if (connect(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
        {
            status = false;
        }
    }

    if (status)
    {
        // Calculate request length.
        requestLen = strlen(request);

        // Send the request to the server.
        if (send(sock, request, requestLen, 0) != requestLen)
        {
            status = false;
        }
    }

    if (status)
    {
        std::cout << "My IP Address: ";

        if ((bytesRcvd = recv(sock, recvBuffer, RCVBUFSIZE - 1, 0)) <= 0)
        {
            status = false;
        }

        if (status && (bytesRcvd >0) && (bytesRcvd < (RCVBUFSIZE-1)))
        {
            recvBuffer[bytesRcvd] = '\0';
            std::cout << recvBuffer << std::endl;
        }
    }

    close(sock);

    return 0;
}

你能为1提供一个示例吗? - user197967
@Levo:我会整理一个例子并在回复中发布。 - Amardeep AC9MF
好的,这里有一个可行的例子。我在cygwin下测试过了 --- 你的情况可能会有所不同。 - Amardeep AC9MF

1
对于C/C++,您需要查找gethostbyname()系列函数(请参见man gethostbyname)和inet_ntoagethostbyname()查询DNS并返回主机名的IP地址列表,您可以使用inet_ntoa打印它们。
这是一个示例程序,将查找指定主机名的IP地址并将其打印出来。注意:我没有放置任何错误检查,请小心!
#include <stdio.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char** argv)
{
   struct hostent* host = gethostbyname(argv[1]);
   int count = 0; 
   char** current_addr = host->h_addr_list;
   while (*current_addr != NULL) 
   { 
       struct in_addr* addr = (struct in_addr*)(*current_addr); 
       printf("address[%d]: %s\n", count, inet_ntoa(*addr));
       ++current_addr;
       ++count;
   }
}

来自我的Kubuntu 10.04机器的一个例子:

mcc@fatback:~/sandbox/c$ ./gethostbyaddr_ex www.yahoo.com
address[0]: 69.147.125.65
address[1]: 67.195.160.76

1
-1,这句话怎么能帮助他找到自己机器的外部IP呢? - unbeli

0
一般来说,这个问题没有正确答案。计算机可能没有互联网IP地址,也可能有一个,甚至可以有多个外部IP地址。如果它只有一个IP地址,你仍然无法在本地获取它,只能通过联系外部服务来获取,该服务将告诉你你连接的位置。你提供的链接就是这样一种服务的例子。

0

实现 url.h 请求你提供的链接 http://www.gnutelephony.org/doxy/bayonne2/a00242.html 不应该太难。我记得曾经用过一个叫做 URLStream.h 的 wget C++ 包装器,它使用了提取运算符,这使得这个任务变得非常容易,但我似乎找不到它了。


0

根据您编写的程序需要运行的上下文,您可能希望通过DBus询问NetworkManager来解决此问题(请参见http://projects.gnome.org/NetworkManager/developers/

这仅适用于桌面系统(甚至不是所有桌面系统...但大多数发行版现在使用NM)

此外,这对于#2没有帮助,但是您可以使用STUN服务器请参阅维基百科


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接