Socket的地址查询函数有很多, 分为主机(host), 网络(net), 协议(proto)和服务(serv), 这些函数完成各种地址查询功能. POSIX.1定义了两个新的函数: getaddrinfo和getnameinfo, 前者把主机名字和服务名字映射到一个地址, 后者将地址转换成主机名或服务器名.
这些函数返回的网络配置信息可能存放在许多地方. 它们可以保存在静态文件中(如/etc/hosts, /etc/services等), 或者可以由命名服务器(如DNS, NIS).
这些地址查询函数大致分为几类: 主机(host), 网络(net), 协议(proto), 服务(serv), 这几类的相关函数也是带有该类别的名字. 下面就这几类分别进行说明:
1. 主机信息查询:
struct
hostent
...
{
char *h_name; /**//* name of host */
char **h_aliases; /**//* pointer to alternate host name array */
int h_addrtype; /**//* address type */
int h_length; /**//* length in bytes of address */
char **h_addr_list; /**//* pointer to array of network addresses */
...
...
}
;
头文件: <netdb.h>
函数原型:
- struct hostent *gethostent();
- void sethostent(int stayopen);
- void endhostent();
说明:
- gethostent: 打开数据文件, 如果数据文件打开则返回文件的下一个条目.
- sethostent: 打开文件, 如果文件已打开, 将其回绕.
- endhostent: 关闭文件.
2. 网络名字和网络号查询:
struct
netent
...
{
char *n_name; /**//* network name */
char **n_aliases; /**//* pointer to alternate network name array */
int n_addrtype; /**//* address type */
uint32_t n_net; /**//* network number */
...
...
}
;
头文件: <netdb.h>
函数原型:
- struct netent *getnetbyaddr(uint32_t net, int type);
- struct netent *getnetbyname(const char *name);
- struct netent *getnetent();
- void setnetent(int stayopen);
- void endnetent();
3. 协议名字和协议号查询:
struct
protoent
...
{
char *p_name; /**//*protocol name */
char **p_aliases; /**//* pointer to alternate protocol name array */
int p_proto; /**//* protocol number */
...
...
}
;
头文件: <netdb.h>
函数原型:
- struct protoent *getprotobyname(const char *name);
- struct protoent *getprotobynumber(int proto);
- struct protoent *getprotoent();
- void setprotoent(int stayopen);
- void endprotoent();
4. 服务查询:
struct
servent
...
{
char *s_name; /**//*service name */
char **s_aliases; /**//* pointer to alternate service name array */
int s_port; /**//* port number */
char *s_proto; /**//* name of protocol */
...
...
}
;
头文件: <netdb.h>
函数原型:
- struct servent *getservbyname(const char *name, const char *proto);
- struct servent *getservbyport(int port, const char *proto);
- struct servent *getservent();
- void setservent(int stayopen);
- void endservent();
5. getaddrinfo函数:
- 原型: int getaddrinfo(const char *restrict host,
const char *restrict service,
const struct addrinfo *restrict hint,
struct addrinfo **restrict res);
- 头文件: <sys/socket.h> <netdb.h>
- 返回值: 成功则返回0, 出错则返回非0错误代码.
- 参数:
- host: 主机名字. 可以是节点名或者是点分十进制表示的主机地址.
- service: 服务名字.
- hint: 过滤地址的模板, 仅使用ai_family, ai_flags, ai_protocol和ai_socktype字段, 剩余字段必须设为0或NULL.
- res: 保存查询结果的指针.
- 说明: 主机名字和服务名字可以都提供, 如果只提供一个, 另一个必须为空.
这个函数里面涉及到一个结构:
struct
addrinfo
...
{
int ai_flags; /**//* customize behavior */
int ai_family; /**//* address family */
int ai_socktype; /**//* socket type */
int ai_protocol; /**//* protocol */
socklen_t ai_addrlen; /**//* length in bytes of address */
struct sockaddr *ai_addr; /**//* address */
char *ai_canonname; /**//* canonical name of host */
struct addrinfo *ai_next; /**//* net in list */
...
...
}
;
getaddrinfo函数返回一个该结构的链表, 我们可以看到该结构中含有一个next成员, 这些链表结点在不用之后, 都需要用freeaddrinfo来逐个释放.
- 原型: void freeaddrinfo(struct addrinfo *ai);
- 头文件: <sys/socket.h> <netdb.h>
addrinfo结构中的ai_flags有以下几种值:
- AI_ADDRCONFIG: 查询配置的地址类型(IPv4或IPv6).
- AI_ALL: 查找IPv4和IPv6地址(仅用于AI_V4MAPPED).
- AI_CANONNAME: 需要一个规范名(而不是别名).
- AI_NUMERICHOST: 以数字格式返回主机地址.
- AI_NUMERICSERV: 以端口号返回服务.
- AI_PASSIVE: socket地址用于监听绑定.
- AI_V4MAPPED: 如果没有找到IPv6地址, 则返回映射到IPv6格式的IPv6地址.
如果getaddrinfo失败, 不能使用perror或strerror来生成错误信息, 应该使用gai_strerror将返回的错误码转换成错误信息:
- 原型: const char *gai_strerror(int error);
- 头文件: <netdb.h>
6. getnameinfo函数:
- 原型: int getnameinfo(const struct sockaddr *restrict addr, socklen_t alen,
char *restrict host, socklen_t hostlen,
char *restrict service, socklen_t servlen,
unsigned int flags);
- 头文件: <sys/socket.h> <netdb.h>
- 参数:
- addr: socket地址.
- alen: socket地址长度.
- host: 主机名.
- hostlen: 主机名长度.
- service: 服务名.
- servlen: 服务名长度.
- flags: 指定转换的控制方式. 可以有如下几种:
- NI_DGRAM: 服务基于数据报而非基于流.
- NI_NAMEREQD: 如果找不到主机名字, 将其作为一个错误对待.
- NI_NOFQDN: 对于本地主机, 仅返回完全限定域名的节点名部分.
- NI_NUMERICHOST: 以数字形式而非名字返回主机地址.
- NI_NUMERICSERV: 以数字形式而非名字返回服务地址(即端口号).
- 说明: 如果host或service非空, 它(们)将指向洋长度问该len字节的缓冲区用于存储返回的名. 如果为空则不返回该名.
以上就是socket的地址查询所有相关函数, 在以后的文章里会有带详细注释的实例代码并进行编译运行讲解.