2011-11-12 35 views
2

一位朋友使用following snippet of code来检索其局域网中主机的本地IP地址。无法使用gethostbyname获取本地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 

看来,一些位进行加扰。我们是否错过了这里的关键转换?

+0

我在Windows上测试了你的代码(VS2010;所以没有使用Exception和QString),它返回的是IP地址的值。 –

+0

也许我的主机保存某些数据的方式有所不同?我被告知,网络具有普遍认同的表示数据的方式,这就是为什么你必须在某些事情上进行“网络到主机”和“主机到网络”的转换。 – Pieter

+0

'inet_ntoa'已被弃用,事实证明。但是接下来我该如何解码'addr_list'中的每个字符串,这些字符串按照网络字节顺序进行编码,然后返回到主机顺序?我在每个角色上尝试了'ntohs()',但是没有得到预期的结果。 – Pieter

回答

0

您建议的方法依赖于“正确的”本地主机名称和“正确”配置的DNS系统。我把“正确的”放在引号中,因为有一个本地的主机名不是用DNS注册的,对于除了你的程序之外的其它目的都是完全有效的。

如果您有连接的套接字(或可以生成连接的套接字),我建议您使用getsockname()查找a本地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.com\n"); 
     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 failed\n"); 
      close(fd); 
      continue; 
     } 
     printf("%s ->", name); 

     if(getnameinfo(res->ai_addr, res->ai_addrlen, name, sizeof name, 0, 0, NI_NUMERICHOST)) { 
      fprintf(stderr, "getnameinfo failed\n"); 
      close(fd); 
      continue; 
     } 
     printf("%s\n", name); 
     close(fd); 
    } 
} 
+0

谢谢 - 这对我来说诀窍。 – Pieter

0

如果你真的使用Qt,你如果不使用Qt,你可以学习,它是怎么做有可以使用此代码

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

+0

我正在做这个计算机网络课程的任务,他们不会允许我们使用外部库来做任何与网络有关的事情,这样我们就可以更深入地了解低层次的东西。这对未来的项目看起来很有用,谢谢。 – Pieter