getaddrinfo
gethostbyname
和gethostbyaddr
这两个函数仅支持IPv4。getaddrinfo
支持名字到地址以及服务到端口的转换,同时支持IPv4和IPv6。getaddrinfo
使用通用套接字结构sockaddr
,隐藏了具体协议的实现。
getaddrinfo
函数原型如下:
#include <netdb.h>
int getaddrinfo(const char *hostname, const char *service,
const struct addrinfo *hints, struct addrinfo **result);
- hostname : 主机名或字符串形式地址("1.1.1.1", "1111::9999")
- service : 服务名或字符串形式端口号
- hints : 期望返回哪些内容,可以为NULL
- results : 查询结果数组指针
- return : 成功返回0,失败返回非0
hints表示希望返回什么结果,比如,只想返回TCP结果,可以让hints指向的ai_socktype等于SOCK_DGRAM。
返回值中的sockaddr可以直接用于sock函数的调用。
struct addrinfo的定义
其中,struct addrinfo
的定义如下:
struct addrinfo {
int ai_flags; /* 标志位 */
int ai_family; /* 协议族: AF_INET|AF_INET6|AF_UNSPEC... */
int ai_socktype; /* sock类型: SOCK_DGRAM|SOCK_STREAM */
int ai_protocol; /* 协议类型: IPPROTO_IP|IPPROTO_IPV6... */
socklen_t ai_addrlen; /* 地址结构长度 */
char *ai_canonname; /* host的正式名称 */
struct sockaddr *ai_addr; /* 地址结构 */
struct addrinfo *ai_next; /* result是个链表结构,ai_next指向下一个addrinfo */
}
hints详解
hint中ai_flags标志及含义如下:
表示 | 含义 |
---|---|
AI_PASSIVE | 套接字被动打开,服务端调用 |
AI_CANONNAME | 返回主机的规范名字 |
AI_NUMERICHOST | 输入的host必须是字符串表示的地址 |
AI_NUMERICSERV | 输入的service必须是字符串表示的端口号 |
AI_V4MAPPED | 如果ai_family等于AF_INET6,但是只有A记录,没有AAAA记录,那么把IPv4地址映射成IPv6地址返回 |
AI_ALL | 即返回AAAA记录,又返回IPv4映射的IPv6地址 |
AI_ADDRCONFIG | 根据主机地址返回结果,如主机是V4的,那么只返回A记录,如果主机是双栈的,那么也返回AAAA记录 |
gai_strerror
以getaddrinfo
的返回值作为参数,gai_strerror
可以获取错误返回值对应的错误信息。
#include <netdb.h>
const char *gai_strerror(error);
- return : 返回指向错误信息的指针
freeaddrinfo
getaddrinfo
返回的addrinfo
中,所有的字段都是动态分配的,调用freeaddrinfo
释放分配的内存。
#include <netdb.h>
void freeaddrinfo(struct addrinfo *ai);
ai应该是addrinfo链表的第一个节点,freeadrinfo会释放链表中的所有内存