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

对于两台主机之间的通信,我需要将主机的IP地址发送到另一个站点。 问题是,如果我请求我的IP地址,可能是我收回本地环回IP地址(127.xxx),而不是网络(以太网)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.xxx */ 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的列表,但提示阻止了这个)

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

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

man getaddrinfo

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

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

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

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

我刚刚遇到这样的情况,当只有/ etc / hosts中有信息时,当我使用getaddrinfo获取IP地址列表时,它每次返回127.0.0.1。 事实certificate,主机名是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,一切正常。

希望这有助于某人。

看看这个:以编程方式发现公共IP

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

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

使用getaddrinfo()

你快到了。 我不确定你是my_iphp获取my_ip

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

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 

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

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

除此之外,你很接近,你应该循环getaddrinfo的结果。 您的代码只获取第一个IP地址,但是后面有一个aip-> ai_next字段…

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