getaddrinfo函数
gethostbyname和getservbyname是基于IPv4协议的,getaddrinfo是协议无关的函数,能够处理名字到地址之间以及服务到端口这两种转换, 返回的是一个sockaddr结构而不是一个地址列表。
#include<netdb.h>
int getaddrinfo(const char *hostname, const char *service, const struct addrinfo*hints, struct addrinfo **result);
//成功返回0, 出错返回非0
四个参数的介绍:
hostname参数: 主机名或地址串(IPv4的点分十进制串或IPv6的十六进制串)
service参数:服务名或十进制端口号数串
hints参数:可以是NULL,也可以是一个addrinfo结构的指针,调用者在这个结构中填入关于期望返回的信心类型的暗示
result参数:返回的结果。
struct addrinfo结构定义
struct addrinfo{
int ai_flags; //AI_PASSIVE, AI_CANONNAME
int ai_family; //AF_XXX
int ai_socktype; //SOCK_XXX
int ai_protocol; //0 or IPPROTO_XXX for IPv4 and IPv6
socklen_t ai_addrlen; //length of ai_addr
char *ai_canonname; //ptr to canonical name for host
struct sockaddr *ai_addr; //ptr to socket address structure
struct addrinfo *ai_next; // ptr to next structure in linked list
};
如果函数成功返回, 那么由result参数指向的变量已被填入一个指针,它指向的是由其中的ai_next成员连接起来的addrinfo结构链表。导致返回多个addrinfo结构的情形有以下两个:
1. 如果与hostname参数关联的地址有多个,那么适用于所请求地址族(由hints的ai_family成员设置)的每个地址都返回一个对应的结构。
2. 如果service参数指定的服务支持多个套接字类型,那么每个套接字类型都可能返回一个对应的结构,具体取决于hints结构的ai_socktype成员。
使用的时候,我们先分配一个hints的addrinfo结构,把它清零后填入需要的字段,再调用getaddrinfo, 然后遍历一个链表逐一尝试每个返回地址。
使用的时候,我们先分配一个hints的addrinfo结构,把它清零后填入需要的字段,再调用getaddrinfo, 然后遍历一个链表逐一尝试每个返回地址。
gai_strerror函数
将getaddrinfo返回的值作为参数,返回一个对应出错信息串的指针
#include <netdb.h>
const char *gai_strerror(int error);
//返回出错信息串的指针
freeaddrinfo函数
由getaddrinfo函数返回的所有存储空间都是动态分配的内存,包括addrinfo结构,ai_addr结构和ai_canonname字符串,需要调用freeaddrinfo释放内存
#include <netdb.h>
void freeaddrinfo(struct addrinfo *ai);
ai参数应指向getaddrinfo返回的链表的第一个结构指针。这个链表的所有结构以及它们指向的任何动态存储空间都将释放掉。如果我们为保存信息而只是复制这个addrinfo结构,然后调用freeaddrinfo,就会有潜在的危险。因为这个结构本身指向动态分配的内存空间都会被释放。
浅复制:只复制这个addrinfo结构而不复制由它转而指向的其他结构
深复制:既复制这个结构,又复制这个结构所指向的所有其他结构
getnameinfo函数
getnameinfo是getaddrinfo的互补函数,以套接字地址为参数,返回描述其中的主机的一个字符串和描述其中服务的另一个字符串
#include <netdb.h>
int getnameinfo(const struct sockaddr *sockaddr, socklen_t addrlen,
char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags);
可重入函数
gethostbyname是不可重入的。getaddrinfo是可重入的。
在一个普通的UNIX进程中发生重入问题的条件是:当它的主控制流中和某个信号处理函数中同时调用函数,会出现不可定义的问题,该函数就是不可重入的。
errno也是不可重入的,并且标准IO函数库也是不可重入的,我们不应该从信号处理函数中调用标准IO函数。