8

我想获取启动我的程序的计算机的 IP 地址,以便能够将其发送到客户端,但我总是得到 0.0.0.1 而不是真实的 IP 地址(例如 127.0.0.1)。

我目前能够获取端口,但不能获取 IP 地址。

我怎么才能得到它?

最好的解决方案是能够使用sockaddr_in. 这是我目前正在做的事情:

int open_connection(char* ip, int* port)
{
  int                   sock;
  struct sockaddr_in    sin;
  socklen_t             len;
  int                   i;

  i = 0;
  len = sizeof(sin);
  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    return (-1);
  bzero(&sin, sizeof(struct sockaddr_in));
  sin.sin_family = AF_INET;
  if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0)
    perror("Error on bind");
  if (getsockname(sock, (struct sockaddr *)&sin, &len) != 0)
    perror("Error on getsockname");
  strcpy(ip, inet_ntoa(sin.sin_addr)); // IP = 0.0.0.0
  *port = sin.sin_port;
  return (sock);
}

编辑:我知道我的思维方式是错误的。所以我的问题是:获取自己的 IP 地址的最佳方法是什么?

4

4 回答 4

13

当您bind()将套接字连接到 0.0.0.0 时,这是该套接字在调用时唯一可用的 IP getsockname()。这意味着套接字绑定到所有本地接口。为了从套接字获取特定的 IP,它必须绑定到特定的 IP。

无论如何,使用套接字 API 获取机器的本地 IP 是错误的方法。一个常见的错误是使用gethostname()withgethostbyname()getaddrinfo()获取本地 IP 列表。通常这是可行的,但它有一些可能导致虚假信息的隐藏陷阱,但人们往往会忽略这个事实,或者甚至一开始都不知道它(我多年来不知道它,但后来我学得更好)。

相反,您确实应该使用特定于平台的 API 来枚举本地网络接口。这将提供更可靠的信息。Windows 具有GetAdaptersInfo()GetAdaptersAddresses(). 其他平台有getifaddrs()。这些将告诉您哪些本地 IP 可用。然后,您可以将bind()套接字连接到 0.0.0.0 以接受任何这些 IP 上的客户端,或者bind()连接到特定 IP 以仅接受该 IP 上的客户端。

于 2013-04-10T01:50:39.083 回答
5

套接字 API 允许您枚举分配给网络接口的 IP 地址,但如果您从路由器后面连接到 Internet,它不会告诉您“真实 IP”是什么。

唯一知道的方法是问外面的人。这就是像 FileZilla FTP Server 这样的服务器如何做到这一点的。他们指示您在服务器设置中配置“ip.php”脚本的 URL,以便它可以向 Internet 询问其公共 IP 地址是什么,以便在被动模式下使用。

您还可以考虑使用STUN,这是一种在 VoIP 中广泛用于发现公共 IP 的协议。

于 2013-04-10T00:38:15.357 回答
1

你可以调用 ioctl(sock, SIOCGIFADDR, adr)

见网络设备(7)

于 2017-01-09T08:17:25.343 回答
0

以下@Remy Lebeau的答案我写了一个返回当前机器地址的函数。我只在 macOS High Sierra 上测试过这个。

interfaec可以是 , 等之间的任何lo0东西en0

ipVersion可以是AF_INETAF_INET6

long int getInternalAddress(char* interface, sa_family_t ipVersion)
{
  struct ifaddrs *ifaddrHead, *ifaddr;
  /* int_8 */
  sa_family_t family;
  int n;
  char *interfaceName;

  if (getifaddrs(&ifaddrHead) != 0)
  {
    fprintf(stderr, "ifaddrs error");
  }

  /* iterate through address list */
  for (ifaddr = ifaddrHead, n = 0; ifaddr != NULL; ifaddr = ifaddr->ifa_next, n++)
  {
    family = ifaddr->ifa_addr->sa_family;
    interfaceName = ifaddr->ifa_name;

    if (!family || family != ipVersion || strcmp(interfaceName, interface)) continue;

    struct sockaddr *addr = ifaddr->ifa_addr;
    struct sockaddr_in* addr_in = (struct sockaddr_in*) addr;
    long int address = addr_in->sin_addr.s_addr;

    freeifaddrs(ifaddrHead);

    return address;
  }

  freeifaddrs(ifaddrHead);

  return 0;
}

要使用它,

int main()
{
  long int address = getInternalAddress((char*) &"en0", AF_INET);
  printf("%li\n", address);

  return 0;
}

我还是C的初学者,如果有什么问题请告诉我。

于 2017-12-23T18:35:44.027 回答