从getaddrinfo

时间:2016-09-16 18:01:49

标签: sockets unix unix-socket

我编写了以下测试程序,无法理解我得到的输出:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>

int main(int argc, char** argv) {
  struct addrinfo* results;
  struct addrinfo hints;
  char buf[INET6_ADDRSTRLEN+1];

  if (argc != 2) {
    exit(-1);
  }

  memset((char*) &hints, 0, sizeof(struct addrinfo));
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;

  int ret = getaddrinfo(NULL, argv[1], &hints, &results);
  if (ret) {
    fprintf(stderr, "%s\n", gai_strerror(ret));
    exit(-1);
  }

  for (struct addrinfo* ai = results; ai != NULL; ai = ai->ai_next) {
    if (ai->ai_family == AF_INET) {
      inet_ntop(AF_INET, ai, buf, INET_ADDRSTRLEN);
    } else {
      inet_ntop(AF_INET6, ai, buf, INET6_ADDRSTRLEN);
    }
    printf("%s\n", buf);
  }

  freeaddrinfo(results);
  return 0;
}

在我的Fedora 23机器上,这将打印:

1.0.0.0
100:0:a00:0:100:0:600:0

我的理解是,返回的IP地址应为INADDR_ANYIN6ADDR_ANY_INIT,两者都应具有值0,即预期输出应为0.0.0.0并且::0。有人可以向我解释这里发生了什么吗?

另一个相关的问题是,如果我的某个接口有host.domain.dom解析的IP,并且我不确定该域是否具有IPv6地址,我该如何获得{{1}我可以用来监听这个域的IPv4和IPv6地址但不绑定任何其他IP的结构?将主机名提供给sockaddr是否正确,即使在这种情况下getaddrinfo标志被忽略了?

1 个答案:

答案 0 :(得分:3)

你不应该将ai本身作为inet_ntop的论据;您应该提供指向实际网络地址的指针,而不是指向addrinfo结构的指针。 inet_ntop()需要in_addrin6_addr结构,因此根据ai->ai_addrsockaddr_in*sockaddr_in6*输入ai->ai_family,然后分别传递其sin_addrsin6_addr字段的地址。

if (ai->ai_family == AF_INET) {
    inet_ntop(AF_INET, &(((sockaddr_in*)(ai->ai_addr))->sin_addr), buf, INET_ADDRSTRLEN);
} else {
    inet_ntop(AF_INET6, &(((sockaddr_in6*)(ai->ai_addr))->sin6_addr), buf, INET6_ADDRSTRLEN);
}

对于你的第二个问题,我相信这会回答:

How to choose a server socket address using getaddrinfo?