无法使用 gethostbyname() 获取本地 IP

Can't obtain local IP using gethostbyname()

本文关键字:获取 IP gethostbyname      更新时间:2023-10-16

一个朋友使用下面的代码片段检索局域网中主机的本地IP地址。

int buffersize = 512;
char name[buffersize];
if(gethostname(name, buffersize) == -1){
    Exception excep("Failed to retrieve the name of the computer");
    excep.raise();
}
struct hostent *hp = gethostbyname(name);
if(hp == NULL){
    Exception excep("Failed to retrieve the IP address of the local host");
    excep.raise();
}
struct in_addr **addr_list = (struct in_addr **)hp->h_addr_list;
for(int i = 0; addr_list[i] != NULL; i++) {
    qDebug() << QString(inet_ntoa(*addr_list[i]));
}

它似乎在他的Mac上工作得很好。他说该数组中的最后一个IP地址是他需要知道的。然而,我在我的Linux笔记本电脑上得到了这些值…

127.0.0.2
192.168.5.1
1.2.3.0

这些看起来与我的适配器使用的值相似,但不相同。以下是ifconfig的一些数据:

eth0      Link encap:Ethernet  HWaddr 1C:C1:DE:91:54:1A  
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
wlan0     Link encap:Ethernet  HWaddr [bleep]
          inet addr:192.168.1.6  Bcast:192.168.1.255  Mask:255.255.255.0

似乎有些位被打乱了。我们是否错过了一个关键的转换?

您建议的方法依赖于"正确"的本地主机名和"正确"配置的DNS系统。我把"正确"放在引号里,因为没有在DNS上注册的本地主机名对于任何目的都是完全有效的,除了你的程序。

如果您有一个已连接的套接字(或可以生成一个已连接的套接字),我建议您使用getsockname()查找一个本地IP地址。(注意:不是本地IP地址——你可以有几个)

下面是一个示例程序。显然,它的大部分是连接到google.com和打印结果。只有对getsockname()的调用与您的问题相关。

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>

int main(int ac, char **av) {
    addrinfo *res;
    if(getaddrinfo("google.com", "80", 0, &res)) {
        fprintf(stderr, "Can't lookup google.comn");
        return 1;
    }
    bool connected = false;
    for(; res; res=res->ai_next) {
        int fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
        if(fd < 0) {
            perror("socket");
            continue;
        }
       if( connect(fd, res->ai_addr, res->ai_addrlen) ) {
           perror("connect");
           close(fd);
           continue;
       }
       sockaddr_in me;
       socklen_t socklen = sizeof(me);
       if( getsockname(fd, (sockaddr*)&me, &socklen) ) {
           perror("getsockname");
           close(fd);
           continue;
       }
       if(socklen > sizeof(me)) {
           close(fd);
           continue;
       }
       char name[64];
       if(getnameinfo((sockaddr*)&me, socklen, name, sizeof name, 0, 0, NI_NUMERICHOST)) {
           fprintf(stderr, "getnameinfo failedn");
           close(fd);
           continue;
        }
        printf("%s ->", name);
       if(getnameinfo(res->ai_addr, res->ai_addrlen, name, sizeof name, 0, 0, NI_NUMERICHOST)) {
           fprintf(stderr, "getnameinfo failedn");
           close(fd);
           continue;
        }
        printf("%sn", name);
        close(fd);
    }
}

如果您确实使用Qt,您可以使用以下代码

foreach (const QHostAddress& address, QNetworkInterface::allAddresses() ) {
        qDebug() << address.toString();
    }

如果你不使用Qt,你可以学习,它是如何制作的。