【问题标题】:C++ Resolve a host IP address from a URLC++ 从 URL 解析主机 IP 地址
【发布时间】:2011-01-10 05:54:23
【问题描述】:

如果给定 Visual C++ 中的 URL,我如何解析主机 IP 地址?

【问题讨论】:

  • 当然。但是几乎每个操作系统的答案都不同。你要哪一个?

标签: c++ url ip


【解决方案1】:

我不确定是否有特定的 C++ 类来进行主机名查找,但您始终可以使用纯 C 来处理此类事情。这是我在 Linux、Mac OS X 和 Windows 上编译和运行的版本。


#include <stdio.h>

#ifdef _WIN32
#  include "winsock.h"
#else
#  include <netdb.h>
#  include <arpa/inet.h>
#endif

static void initialise(void)
{
#ifdef _WIN32
    WSADATA data;
    if (WSAStartup (MAKEWORD(1, 1), &data) != 0)
    {
        fputs ("Could not initialise Winsock.\n", stderr);
        exit (1);
    }
#endif
}

static void uninitialise (void)
{
#ifdef _WIN32
    WSACleanup ();
#endif
}

int main (int argc, char *argv[])
{
    struct hostent *he;

    if (argc == 1)
        return -1;

    initialise();

    he = gethostbyname (argv[1]);
    if (he == NULL)
    {
        switch (h_errno)
        {
            case HOST_NOT_FOUND:
                fputs ("The host was not found.\n", stderr);
                break;
            case NO_ADDRESS:
                fputs ("The name is valid but it has no address.\n", stderr);
                break;
            case NO_RECOVERY:
                fputs ("A non-recoverable name server error occurred.\n", stderr);
                break;
            case TRY_AGAIN:
                fputs ("The name server is temporarily unavailable.", stderr);
                break;
        }
    }
    else
    {
        puts (inet_ntoa (*((struct in_addr *) he->h_addr_list[0])));
    }

    uninitialise ();

    return he != NULL;
}

编译后,提供主机名作为参数:

$ ./a.out stackoverflow.com
69.59.196.211

【讨论】:

  • 在Windows上编译时,请使用cl resolve.c /link ws2_32.lib,否则链接时会出现未定义符号错误。
  • 哈!在 Windows 上,如果找不到该名称,由于某种原因,它的 h_errno 包含 NO_ADDRESS 而不是 HOST_NOT_FOUND
  • gethostbyname 已被getaddrinfo 取代。静态缓冲区?只有 IPV4?加入21世纪! :P
  • @asveikau:在单线程简单案例示例程序中,不需要其他任何东西。不要用大锤敲钉子。
  • 我的经验是,您永远不知道您的代码将如何或在什么上下文中被重用。现代而强大的 C 编码要求避免这些问题。这并不难。 (在提供其他人可以学习的示例代码时,以正确的方式进行教学也尤为重要。)
【解决方案2】:

要在 Windows 下使用套接字功能,您必须首先调用 WSAStartup,指定您想要的 Winsock 版本(为了您的目的,1.1 可以正常工作)。然后可以拨打gethostbyname获取主机地址。完成后,您应该调用 WSACleanup。把这些放在一起,你会得到这样的结果:

#include <windows.h>
#include <winsock.h>
#include <iostream>
#include <iterator>
#include <exception>
#include <algorithm>
#include <iomanip>

class use_WSA { 
    WSADATA d; 
    WORD ver;
public:
    use_WSA() : ver(MAKEWORD(1,1)) { 
        if ((WSAStartup(ver, &d)!=0) || (ver != d.wVersion))
            throw(std::runtime_error("Error starting Winsock"));
    }
    ~use_WSA() { WSACleanup(); }    
};

int main(int argc, char **argv) {
    if ( argc < 2 ) {
        std::cerr << "Usage: resolve <hostname>";
        return EXIT_FAILURE;
    }

    try { 
        use_WSA x;

        hostent *h = gethostbyname(argv[1]);
        unsigned char *addr = reinterpret_cast<unsigned char *>(h->h_addr_list[0]);
        std::copy(addr, addr+4, std::ostream_iterator<unsigned int>(std::cout, "."));
    }
    catch (std::exception const &exc) {
        std::cerr << exc.what() << "\n";
        return EXIT_FAILURE;
    }

    return 0;
}

【讨论】:

    【解决方案3】:

    简单如下:

    Linux

    #include <stdio.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    int main()
    {
    struct hostent *he=gethostbyname("www.stackoverflow.com");
    char *ip=inet_ntoa(*(struct in_addr*)he->h_addr_list[0]);
    printf(ip);
    }
    

    Windows

    #include <stdio.h>
    #include <winsock.h>
    int main()
    {
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2,2),&wsaData);
    struct hostent *he=gethostbyname("www.stackoverflow.com");
    char *ip=inet_ntoa(*(struct in_addr*)he->h_addr_list[0]);
    printf(ip);
    }
    

    Android

    #include <stdio.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    #include <sys/socket.h>
    int main()
    {
    struct hostent *he=gethostbyname("www.stackoverflow.com");
    char *ip=inet_ntoa(*(struct in_addr*)he->h_addr_list[0]);
    printf(ip);
    }
    

    为 Android 编译

    在拱臂上使用这些标志:-Wl,-s -lz -rdynamic -fPIE -pie

    完成后,通过adb

    运行
    adb push <binfile> /data/local/tmp
    
    adb shell /data/local/tmp/<binfile>
    

    【讨论】:

      【解决方案4】:
      struct hostent *he;
      
      if ((he = gethostbyname("localhost") == NULL) {
          // Handle error: Failed
      }
      

      IP 地址为he-&gt;h_addr。适用于 windows、linux 和最有可能的 macos。

      【讨论】:

      • 我什么也没得到,只是 localhost 和例如stackoverflow.com 的“表达式无法评估”。与我裸露,因为我不是 C++ 工程师,只是学习。如果我删除 if 语句,并简单地将 gethostname 分配给他,使用 URL,似乎什么都没有发生。
      【解决方案5】:

      解析 URL 以获取主机名。然后在您的平台上调用 gethostbyname 或相应的 API 以获取 IP 地址。如果您正在解析 HTTP 标头,请查找 HostName 标头以确定主机名。

      【讨论】:

        【解决方案6】:

        gethostbyname?

        【讨论】:

          猜你喜欢
          • 2013-03-25
          • 2010-11-05
          • 2011-03-12
          • 1970-01-01
          • 2014-02-26
          • 2014-10-13
          • 2021-10-08
          • 2013-01-29
          • 2012-08-04
          相关资源
          最近更新 更多