一、getnameinfo函数概述
getnameinfo是网络编程中常用的函数之一,它的作用是将IP地址和端口转换成可读的主机名和服务名。
该函数定义于sys/socket.h和netdb.h头文件中,它的原型如下:
int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen, char *restrict host, socklen_t hostlen, char *restrict serv, socklen_t servlen, int flags);
其中,参数sa是一个指向要转换的sockaddr结构体的指针,salen是这个结构体的长度;
参数host和serv分别是主机名和服务名的存放缓冲区,hostlen和servlen是它们的长度;
参数flags的使用可以决定返回结果的格式,常用的值有NI_NUMERICHOST和NI_NUMERICSERV。
二、将IP地址转换为主机名
在使用getnameinfo函数将IP地址转换为主机名时,我们需要先将IP地址存放到一个sockaddr结构体中。
下面是具体的转换过程:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> int main(int argc, char *argv[]) { struct addrinfo hints, *res; char ip_str[INET6_ADDRSTRLEN]; void *addr; if (argc != 2) { fprintf(stderr,"usage: %s ip\n", argv[0]); exit(1); } memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; // Allow IPv4 or IPv6 hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; // For wildcard IP address if (getaddrinfo(argv[1], NULL, &hints, &res) != 0) { fprintf(stderr, "getaddrinfo error\n"); exit(1); } // convert address to a string if (res->ai_family == AF_INET) { // IPv4 struct sockaddr_in *ipv4 = (struct sockaddr_in *)res->ai_addr; addr = &(ipv4->sin_addr); } else { // IPv6 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)res->ai_addr; addr = &(ipv6->sin6_addr); } // convert the IP to a string and print it inet_ntop(res->ai_family, addr, ip_str, sizeof(ip_str)); printf("IP address: %s\n", ip_str); // convert IP to host name char host[NI_MAXHOST]; if (getnameinfo(res->ai_addr, res->ai_addrlen, host, NI_MAXHOST, NULL, 0, 0) != 0) { fprintf(stderr, "getnameinfo error\n"); exit(1); } printf("Host name : %s\n", host); freeaddrinfo(res); return 0; }
在这个例子中,我们通过命令行参数传入了需要转换的IP地址,然后使用getaddrinfo函数将这个地址转换为一个sockaddr结构体。
接着,我们使用inet_ntop函数将IP地址转换为一个字符串,并打印出来。
最后,我们使用getnameinfo函数将该IP地址转换为主机名,并打印出来。
需要注意的是,在使用getnameinfo函数时,可以通过flags参数来控制输出的格式。
三、将主机名转换为IP地址
和将IP地址转换为主机名类似,我们先需要用getaddrinfo函数将主机名转换为一个sockaddr结构体,然后再调用getnameinfo函数来将它转换为IP地址。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> int main(int argc, char *argv[]) { struct addrinfo hints, *res; char ip_str[INET6_ADDRSTRLEN]; if (argc != 2) { fprintf(stderr,"usage: %s hostname\n", argv[0]); exit(1); } memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo(argv[1], NULL, &hints, &res) != 0) { fprintf(stderr, "getaddrinfo error\n"); exit(1); } // convert the socket address to a string and print it int i; for(i = 1, res = res->ai_next; res; res = res->ai_next, ++i) { void *addr; char* ipver; if (res->ai_family == AF_INET) { // IPv4 struct sockaddr_in *ipv4 = (struct sockaddr_in *)res->ai_addr; addr = &(ipv4->sin_addr); ipver = "IPv4"; } else { // IPv6 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)res->ai_addr; addr = &(ipv6->sin6_addr); ipver = "IPv6"; } inet_ntop(res->ai_family, addr, ip_str, sizeof ip_str); printf("%s address %d: %s\n", ipver, i, ip_str); } freeaddrinfo(res); return 0; }
在这个例子中,我们通过命令行参数传入了需要转换的主机名,然后使用getaddrinfo函数将该主机名转换为一个sockaddr结构体。
然后,我们遍历所有的结果,将其中的IP地址转换为字符串,并打印出它们的版本(IPv4或IPv6)和序号。
四、小结
getnameinfo是网络编程中一个非常重要的函数,它可以方便地将IP地址和端口转换为可读的主机名和服务名。
在使用该函数时需要注意一些细节,比如flags参数可以控制输出的格式。通过这篇文章的介绍,相信读者已经对getnameinfo函数有了更深入的了解。