getaddrinfo和getnameinfo的正确使用方法

3

在我的C程序中,我使用getaddrinfo函数从主机名获取IP地址,使用getnameinfo函数从IP地址获取主机名。这两个函数是互补的。我在man getaddrinfo中读到必须使用freeaddrinfo()函数释放为动态分配的链表res分配的内存。因此,我的代码如下:

if ((err = getaddrinfo(argv[1], NULL, &hints, &res)) != 0) {
  printf("error %d\n", err);
  return 1;
}

addr.s_addr = ((struct sockaddr_in *)(res->ai_addr))->sin_addr.s_addr;
printf("%s\n", inet_ntoa(addr));

freeaddrinfo(res);

但是对于getnameinfo,我没有看到任何类似的函数,即freenameinfo
当使用getaddrinfo时,为什么需要释放内存,但是使用getnameinfo时不需要?为什么需要释放内存?在之前使用gethostbyaddr时,没有必要释放内存。这是为什么不同呢? getaddrinfo相对于gethostbyaddr的优势是什么?后者是否已被弃用,只能使用前者?为什么?

你可能会喜欢Beej的网络编程指南,特别是第9.7节 - pmg
1个回答

6

getaddrinfo的手册中可以看到,它会返回一个动态分配的链表。 由于它执行了内存分配,因此它也会处理内存释放。

freeaddrinfo()函数释放为动态分配的链表res分配的内存。

还要注意函数签名包括struct addrinfo **,这是一个很好的提示,说明库函数正在代表您进行分配并将指针返回给您。

   int getaddrinfo(const char *node, const char *service,
                       const struct addrinfo *hints,
                       struct addrinfo **res);

对于getnameinfo(),它要求调用者(即你)分配const struct sockaddr *,因此调用者(即你)有责任释放它,并且没有相应的库调用来释放它。
   int getnameinfo(const struct sockaddr *sa, socklen_t salen,
                   char *host, size_t hostlen,
                   char *serv, size_t servlen, int flags);

根据gethostbyaddr的手册页面,它已经被声明为过时。

gethostbyname*()gethostbyaddr*()herror()hstrerror()函数已经过时。应用程序应该使用getaddrinfo(3)getnameinfo(3)gai_strerror(3)代替。

在这一点上,我通常停止阅读,并停止使用gethostbyaddr,而更喜欢使用getaddrinfo

为什么这些函数被废弃?可能有很多原因,但是维基百科告诉我们,传统函数不支持IPv6,并且正如@R..在下面提到的那样,它们不是线程安全的。


@R..,谢谢,我找到了一个参考并更新了答案。 - merlin2011
getaddrinfo 在错误情况下需要释放内存吗?我没有在任何地方看到这方面的信息。我的程序使用了它,唯一没有调用 free 的地方就是在错误处理上,但 valgrind 报告了内存泄漏。 - The Quantum Physicist
@TheQuantumPhysicist,老实说我不确定。如果没有任何文档记录,那么很可能需要查阅源代码 - merlin2011
@merlin2011 这很合理。感谢您的时间。 - The Quantum Physicist

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接