如何在C中获取我的非环回网络IP地址?

时间:2009-03-09 10:14:43

标签: c networking network-programming communication

对于两台主机之间的通信,我需要将主机的IP地址发送到另一个站点。问题是,如果我请求我的IP地址,可能是我恢复了我的本地环回IP地址(127.x.x.x),而不是网络(以太网)IP地址。

我使用以下代码:

char myhostname[32];


gethostname(myhostname, 32);
hp = gethostbyname(myhostname);
unsigned my_ip = *(unsigned*)(hp->h_addr);

if( (my_ip % 256) == 127) {
  /* Wrong IP adress as it's 127.x.x.x */
  printf("Error, local IP address!");
  return;
}

解决问题的唯一方法是确保/ etc / hosts中的主机名在真实网络地址后面,而不是本地环回(例如Ubuntu的默认值)。

有没有办法在不依赖/ etc / hosts的内容的情况下解决这个问题?

编辑:我更改了上面的代码,因此它使用了getaddrinfo,但我仍然回到环回设备的号码(127.0,0,1),而不是真正的IP地址:

struct addrinfo hint = {0};
struct addrinfo *aip = NULL;
unsigned ip = 0;
struct sockaddr_in *sinp = NULL;

hint.ai_family = AF_INET; /* IPv4 */
hint.ai_socktype = SOCK_STREAM;

if(getaddrinfo(hostname, NULL, &hint, &aip) != 0) {
    return 0;
}
sinp = (struct sockaddr_in *) aip->ai_addr;
ip   = *(unsigned *) &sinp->sin_addr;

(我曾经用三个SOCK_STREAM,SOCK_DGRAM和SOCK_RAW取回了3个addrinfo的列表,但提示阻止了这个)

所以我的问题仍然存在......

10 个答案:

答案 0 :(得分:9)

POSIX函数getaddrinfo()返回给定主机名的地址链接列表,因此您只需要查看该列表并找到非环回地址。

请参阅man getaddrinfo

答案 1 :(得分:4)

不是答案,而是相关评论:请注意,只要您开始在数据包内容中发送寻址信息,您就有可能使您的应用无法在NAT:ing路由器和/或通过防火墙。

这些技术依赖于IP数据包标头中的信息来跟踪流量,如果应用程序在数据包内交换寻址信息,它们在此检查中仍然不可见,它们可能会中断。

当然,这可能与您的应用程序完全无关,但我认为值得在此背景下指出。

答案 2 :(得分:4)

发送的地址将包含在发送的数据包中......无需复制此信息。它是在接受来自远程主机的通信时获得的(参见beej的网络指南,特别是accept()上的部分)

答案 3 :(得分:3)

我遇到的情况是,当只有/ etc / hosts中有信息时,当我使用getaddrinfo获取IP地址列表时,它每次返回127.0.0.1。事实证明,主机名是localhost的别名......通常很容易忽略。这是发生的事情:

/ etc / hosts文件:
127.0.0.1 localhost.localdomain localhost foo
:: 1 localhost6.localdomain6 localhost6
172.16.1.248 foo
172.16.1.249 bie
172.16.1.250 bletch

所以,现在,当你用host =“foo”调用getaddrinfo时,它会返回127.0.0.1 3次。这里的错误是foo出现在“127.0.0.1”和“172.16.1.248”的行上。一旦我从“127.0.0.1”的行中删除了foo,一切正常。

希望这有助于某人。

答案 4 :(得分:1)

看看这个: Discovering public IP programmatically

请注意,在某些情况下,计算机可能有多个非环回IP地址,在这种情况下,该问题的答案会告诉您如何获取暴露于互联网的IP地址。

答案 5 :(得分:0)

即使计算机只有一个物理网络接口(假设可能存在也可能不存在,即使上网本有两个 - 以太网和WLAN),VPN也可以添加更多的IP地址。无论如何,另一方的主机应该能够确定主机用来联系它的IP。

答案 6 :(得分:0)

答案 7 :(得分:0)

你快到了。我不确定你是如何从my_ip获得hp的。

gethostbyname()返回指向hostent结构的指针,该结构具有h_addr_list字段。

h_addr_list字段是绑定到该主机的所有IP地址的以空字符结尾的列表。

我认为你得到的是环回地址,因为它是h_addr_list中的第一个条目。

编辑:它应该是这样的:

gethostname(myhostname, 32);
hp = gethostbyname(myhostname);
unsigned my_ip = *(unsigned*)(hp->h_addr);

for (int i = 0; hp->h_addr_list[i] != 0; ++i) {
  if (hp->h_addr_list[i] != INADDR_LOOPBACK) {
    // hp->addr_list[i] is a non-loopback address
  }
}
// no address found

答案 8 :(得分:0)

如果/ etc / hosts仍然存在且仍然相同,则查找h_addr_list的所有条目都无济于事。

答案 9 :(得分:0)

您的新代码硬件使用IPv4(在hint.ai_family字段中),这是一个糟糕的主意。

除此之外,你很接近,你应该循环getaddrinfo的结果。您的代码只获得了第一个IP地址,但是有一个aip-> ai_next字段可以跟随......

struct addrinfo {
       ...
       struct addrinfo *ai_next;       /* next structure in linked list */
};