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

Posted

技术标签:

【中文标题】如何在 C 中获取我的非环回网络 IP 地址?【英文标题】:How to get my non-loopback network ip address in C? 【发布时间】:2010-10-12 03:48:09 【问题描述】:

对于两个主机之间的通信,我需要将我的主机的 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 的列表,但提示阻止了它)

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

【问题讨论】:

gethostbyname 已被弃用很多年(原因之一是它只适用于一个地址系列)。如 qrdl 所述,您应该使用 getaddrinfo 好的,谢谢您的信息。这个原始代码是 12 岁以上。 【参考方案1】:

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

man getaddrinfo

【讨论】:

【参考方案2】:

不是答案,而是相关评论:请注意,一旦您开始在数据包内容中发送地址信息,您就有可能使您的应用程序无法跨 NAT:ing 路由器和/或防火墙工作.

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

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

【讨论】:

是的,这无关紧要,因为它总是在本地 LAN 上运行,但是您的观点确实与更大规模的应用程序有关。 小心:代码的持久性超出了您的初衷。请注意,总有一天,有人会想在本地局域网之外运行它。 (这可能没有任何意义,但他们会想要这样做)。【参考方案3】:

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

【讨论】:

【参考方案4】:

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

/etc/hosts 文件: 127.0.0.1 localhost.localdomain 本地主机富 ::1 localhost6.localdomain6 localhost6 172.16.1.248 富 172.16.1.249 别 172.16.1.250 废话

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

希望这对某人有所帮助。

【讨论】:

是的,这很可能是问题所在,我自己也发现了。您的系统应该注意确保您的主机名设置为正确的 IP 地址。因此,没有以太网连接可能没问题,但是一旦添加了额外的连接,系统就应该更改 /etc/hosts。【参考方案5】:

看看这个: Discovering public IP programmatically

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

【讨论】:

我需要从 C 中获取它,而不是从 shell 脚本或 java 中获取 至少接受的答案仍然相关——您可以从 C 访问该网站。【参考方案6】:

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

【讨论】:

【参考方案7】:

使用getaddrinfo()

【讨论】:

【参考方案8】:

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

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

【讨论】:

gethostbyname 自 1997 年 4 月起已弃用...(RFC 2133 版本) 我将现在从 hp 获取 my_ip 的行添加到原始问题中。【参考方案9】:

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

【讨论】:

什么意思,应该或不应该将 wat 放在 /etc/hosts 中?问题是在我们的普通系统(RHEL)上,主机名不是放在 127.0.0.1 条目之后(而是真正的 eth0 地址),但在像 Ubuntu 这样的系统上,他们把主机名放在 127.0.0.1 条目之后。跨度> 尝试删除(如果有疑问,重命名)文件 /etc/hosts,然后您将直接获得 eth0 IP,如果您可以接受的话。可能是更糟糕的选择,但如果您只需要担心一台机器......【参考方案10】:

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

除此之外,您已经很接近了,您只需遍历 getaddrinfo 的结果。您的代码只获取了第一个 IP 地址,但后面还有一个 aip->ai_next 字段...

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

【讨论】:

在 getaddrinfo 结构后放置断点并浏览 ai_next 不会显示所有不同的 ip 地址,我只能得到本地地址或真实的以太网地址,具体取决于 /etc/ 中的主机名主机已放置。 正如我在对该问题的评论中所说,无论如何,算法 是有缺陷的。我的回答只是解释如何实现有缺陷的算法:-)

以上是关于如何在 C 中获取我的非环回网络 IP 地址?的主要内容,如果未能解决你的问题,请参考以下文章

linux上的环回接口地址是多少?

如何在 Go 中获取本地 IP 地址?

C# - 连接到 (RAS) *** 时如何获取 IP 地址

OMNIORB:在 IOR 中使用 Vmnet8 ip,在服务器外部无法访问

如何获取本地计算机的 IP 地址?

环回接口以及MTU