C++从URL解析主机IP地址

10

如何在Visual C++中,根据URL解析主机IP地址?


当然可以。但每个操作系统的答案都不同。你要哪一个? - D.Shawley
6个回答

13

我不确定是否有一个特定的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

1
gethostbyname已被getaddrinfo取代。静态缓冲区?仅限IPv4?加入21世纪吧!:P - asveikau
1
@asveikau:在单线程简单示例程序中,不需要其他任何东西。不要用大锤子打钉子。 - dreamlax
我的经验是,你永远不知道你的代码将在什么情况下被重用。现代和强大的C编码需要避免这些问题。这并不难。(当提供其他人可以学习的示例代码时,教授正确的方法尤为重要。) - asveikau
@asveikau:我不同意,任何人盲目地复制/重用代码而不是通过阅读适用的文档了解其作用,都会陷入麻烦。只有符合您自己的一组要求的代码重用才有用。了解一个“片段”代码是否符合在您自己的代码中重用的要求的唯一方法是研究该代码或任何附带的文档。 - dreamlax
在大型代码库中,如果无法对每一行受影响的代码进行彻底审查(例如重构、库代码突然链接到新位置等情况),则需要保持良好的态度,直到成千上万行代码被批量“移动”。我的前面的括号注释仍然适用-如果通过示例代码教授某人新知识,请不要教他们像90年代那样编写代码,否则他们将在不知不觉中受到这些限制。 - asveikau
显示剩余2条评论

8

要在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;
}

2

操作简单:

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 应用

在 arch-arm 上使用以下标志:-Wl,-s -lz -rdynamic -fPIE -pie

完成后,通过 adb 运行它。

adb push <binfile> /data/local/tmp

adb shell /data/local/tmp/<binfile>

1
struct hostent *he;

if ((he = gethostbyname("localhost") == NULL) {
    // Handle error: Failed
}

IP地址将在he->h_addr中。适用于Windows、Linux,很可能也适用于macOS。


我什么都没得到,无论是本地主机还是例如http://www.stackoverflow.com,都只是一个“表达式无法评估”。请耐心等待,因为我不是C++工程师,只是在学习。如果我删除if语句,并简单地将gethostname分配给he,再加上URL,似乎什么也没有发生。 - George Johnston

0

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


-2

gethostbyname?


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