这个函数与getaddrinfo互补,它以一个套接口地址为参数,返回一个描述主机的字符串和一个描述服务的字符串。
头文件
#include <sys/socket.h>
#include <netdb.h>
函数原型
int getnameinfo(const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen,
char *serv, size_t servlen, int flags);
参数
flags该标志的说法是,改变功能的默认操作的标志。默认情况下,应返回主机的完全限定域名(FQDN),但是:
- 如果设置了标志位NI_NOFQDN,则只应为本地主机返回FQDN的节点名称部分。
- 如果设置了标志位NI_NUMERICHOST ,则在所有情况下都应返回sa参数指向的套接字地址结构中包含的地址的数字形式而不是其名称。
- 如果设置了标志位NI_NAMEREQD,则如果找不到主机名,则应返回错误。
- 如果设置了标志位NI_NUMERICSERV,则在所有情况下都应返回服务地址的数字形式(例如,其端口号)而不是其名称。
- 如果设置了标志位NI_NUMERICSCOPE,则应返回范围标识符的数字形式(例如,接口索引)而不是其名称。如果sa参数不是IPv6地址,则应忽略此标志。
- 如果设置了标志位NI_DGRAM,则表明该服务是数据报服务(SOCK_DGRAM)。默认行为应假定该服务是流服务(SOCK_STREAM)。
返回值
getnameinfo()的零返回值表示成功完成; 非零返回值表示失败。错误的可能值列在“错误”部分中。
成功完成后,getnameinfo()将在提供的缓冲区中返回节点和服务名称(如果请求)。返回的名称始终以空字符结尾的字符串。
错误
如果出现以下情况,getnameinfo()函数将失败并返回相应的值:
[EAI_AGAIN]
目前无法解析该名称。未来的尝试可能成功。
[EAI_BADFLAGS]
该标志有一个无效值。
[EAI_FAIL]
发生了不可恢复的错误。
[EAI_FAMILY]
未识别地址系列或指定系列的地址长度无效。
[EAI_MEMORY]
存在内存分配失败。
[EAI_NONAME]
名称无法解析提供的参数。
NI_NAMEREQD已设置且无法找到主机名,或者nodename和servname均为null。
[EAI_OVERFLOW]
参数缓冲区溢出。node参数或service参数指向的缓冲区太小。
[EAI_SYSTEM]
发生系统错误。错误代码可以在errno中找到。
addrinfo 结构体定义
struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
struct sockaddr *ai_addr;
char *ai_canonname;
struct addrinfo *ai_next;
};
示例1:
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int ret;
char *ptr;
char hostname[128] = {0};
char servername[128] = {0};
struct sockaddr_in addr_dst;
ptr = argc < 2 ? "180.101.49.11" : argv[1];
memset(&addr_dst,0,sizeof(addr_dst));
addr_dst.sin_family = AF_INET;
addr_dst.sin_addr.s_addr = inet_addr(ptr);
ret = getnameinfo((struct sockaddr *)&addr_dst, sizeof(addr_dst), hostname, sizeof(hostname), servername, sizeof(servername), 0);
if (ret != 0)
{
fprintf(stderr, "error in getnameinfo: %s \n", gai_strerror(ret));
}
else
{
printf("hostname IP: %s \n", hostname);
printf("servername IP: %s \n", servername);
}
exit(EXIT_SUCCESS);
}
示例2:
/* hostname_to_ip hostname */
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s hostname\n", argv[0]);
exit(EXIT_FAILURE);
}
struct addrinfo hints;
struct addrinfo *result, *result_pointer;
int ret;
/* obtaining address matching host */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_CANONNAME;
hints.ai_protocol = 0; /* any protocol */
ret = getaddrinfo(argv[1], NULL, &hints, &result);
if (ret != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
exit(EXIT_FAILURE);
}
/* traverse the returned list and output the ip addresses */
for (result_pointer = result; result_pointer != NULL; result_pointer = result_pointer->ai_next)
{
char hostname[1025] = "";
//flags = NI_NUMERICHOST 表示任何情况下都返回数字形式地址
ret = getnameinfo(result_pointer->ai_addr, result_pointer->ai_addrlen, hostname, sizeof(hostname), NULL, 0, NI_NUMERICHOST);
if (ret != 0)
{
fprintf(stderr, "error in getnameinfo: %s \n", gai_strerror(ret));
continue;
}
else
{
printf("IP: %s \n", hostname);
}
}
freeaddrinfo(result);
exit(EXIT_SUCCESS);
}
打印hostname有些事域名,如8.8.8.8或114.114.114.114,有些是IP的二进制子串;
参考资料
http://pubs.opengroup.org/onlinepubs/009695399/functions/getnameinfo.html
https://blog.csdn.net/xiexingshishu/article/details/40018589
https://blog.csdn.net/jctian000/article/details/81912346
http://cache.baiducontent.com/c?m=9d78d513d99616e904becb29564a833b0d13c03d338d96533dc3923b8e791e040271e3cc766052548d98297001d81801b5ed62377d5b78aac888d91086ffc5352f8a24346d1f855c11d304acc04127c424875a9ef55fb8e4&p=9263c21a86cc42a41a9fc7710f53&newp=8e49f90ecd8512a05abd9b7d065092695d0fc20e3ad2d501298ffe0cc4241a1a1a3aecbf22211a00d2c17c660aad4b5fecfa31723d0034f1f689df08d2ecce7e&user=baidu&fm=sc&query=getnameinfo&qid=a8eb58a4000006e4&p1=7