在C中使用bind()时获取错误的IP地址

Get wrong IP address when using bind() in C

本文关键字:获取 取错误 地址 IP bind      更新时间:2023-10-16

我在C中使用套接字编程API。在TCP客户端程序中,我使用bind(),然后使用getsockname()(在调用connect()之前)来获取本地机器的IP地址和端口号。然而,我只能得到正确的端口号,同时得到错误的IP地址(零)。

所以我想问是否有任何方法可以正确地获得本地机器的正确IP地址(在调用connect()之前)?

没有一种简单或可移植的方法来完成您想要做的事情。在您的案例中,bind()getsockname()的行为是正确的。

您的程序不应以任何方式依赖或要求主机的IP地址。如果是这样,那么您的程序中可能存在一些设计问题。

问问自己,一台有两个网络接口、连接到两个不同网络和多个IP地址的计算机的IP地址是多少?

     Network 1                  Network 2
...-----------+--            --+-----------...
                             /
     192.0.2.1              /  198.51.100.2
          eth0  +------------+  eth1
                |  Computer  |
                +------------+

问:在这种情况下,您希望看到什么IP地址?

答案是没有正确的答案,你的程序甚至不应该为此而烦恼。您的程序应该更关心建立通信,为此您只需要目标IP或主机名。操作系统将找到建立通信的方法(对于面向连接的流,它可能能够为您提供选择与该目标通信的本地地址)。

您可以使用gethostname()检索当前主机名,并使用该名称尝试查找IP地址,但仍有很多问题:

  1. 不要求也不保证主机名具有任何关联的IP地址
  2. 在比您想象的更多的情况下,与主机名相关的IP地址是127.0.0.1,这是没有用的(大多数Linux发行版将其添加到/etc/hosts文件中)
  3. 即使你从主机名中获得了一个IP地址,它也不太可能有任何用处(就像上面的情况2,或者NAT后面的本地IP地址,或者错误网络接口的IP)

所以,你一开始就不应该依赖这些信息。

一种可移植的方法是首先调用gethostname(),然后调用gethostbyname()。

即。

char hostname[256], ipaddress[256];
if (gethostname(hostname, sizeof(hostname)) != SOCKET_ERROR) {
    struct hostent *phe = gethostbyname(hostname);
    if (phe != NULL && phe->h_addr_list[0] != NULL) {
        struct in_addr addr;
        memcpy(&addr, phe->h_addr_list[0], sizeof(struct in_addr));
        strcpy(ipaddress, inet_ntoa(addr));
    }
}

您可以使用gethostname获取主机名,然后使用gethostbyname获取IP地址。

如果您绑定到INADDR_ANY,那么这就是您将从getsockname()获得的地址。

特别是,在具有多个接口的机器上,套接字一侧使用的地址将取决于路由表和远程客户端的地址。

例如,如果你在环回接口上连接到自己,你会在127.0.0.1上,而如果你连接到外面的人,那么它将是你以太网接口的地址之一。

如果并且仅当您确实需要绑定到已知地址时,正确的方法是枚举机器的网络接口(如果您在Linux上,请参阅man netdevice),然后向bind()提供特定的所需地址。

您可以使用gethostip()来获取主机IP地址。