对于两台主机之间的通信,我需要将主机的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的列表,但提示阻止了这个)
所以我的问题仍然存在......
答案 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 */
};