头文件 #include <netdb.h>
返回hostent构造体类型指针:
struct hostent { char h_name; / official name of host / char h_aliases; / alias list / int h_addrtype; / host address type / int h_length; / length of address / char h_addr_list; / list of addresses / }
这个函数的局限是只能返回IPv4地址,并且不许可调用者指定所需地址类型的任何信息,返回的构造只包含了用于存储 IPv4 地址的空间。POSIX规范预警可能会在将来某个版本中撤销gethostbyname函数。
从POSIX规范中撤销该函数意在声明新的程序不该在利用它,鼓励在新的程序中改用getaddrinfo函数。
函数原型:
int gethostbyname_r(const char name, struct hostent ret, char buf, size_t buflen, struct hostent result, int h_errnop);
gethostbyname_r()函数是gethostbyname()函数的可重入版本,两个函数的功能是一样的。
2. gethostbyname2函数:struct hostent gethostbyname2(const char name, int af);
它的事情事理类似于gethostbyname(),但是许可指定地址必须属于的地址族,当af参数为AF_INET时,gethostbyname2和gethostbyname一样,即查找并返回IPv4地址。当af参数为AF_INET6时,gethostbyname2只查找AAAA记录并且返回IPv6地址。
头文件:同上。
返回hostent构造体类型指针:同上。
函数原型:
int gethostbyname2_r(const char name, int af, struct hostent ret, char buf, size_t buflen, struct hostent result, int h_errnop);
gethostbyname2_r()函数是gethostbyname2()函数的可重入版本,两个函数的功能是一样的。
3. getaddrinfo函数将主机名、主机地址、做事名和端口的字符串表示转换成套接字地址构造体。它是已弃用的getgostbyname和getservbyname函数的新的替代品。和以前的那些函数不同,这个函数是可以重入的,适宜于任何协议,函数把协议干系性完备隐蔽在这个库函数内部。运用程序只要处理由getaddrinfo函数填写的套接口地址构造。
函数原型:
int getaddrinfo( const char node, const char service, const struct addrinfo hints, struct addrinfo res);
1)nodename:节点名可以是主机名,也可以是数字地址。(IPV4的10进点分,或是IPV6的16进制);
2)servname:包含十进制数的端口号或做事名如(ftp,http);
3)hints:是一个空指针或指向一个addrinfo构造的指针,由调用者填写关于它所想返回的信息类型的线索;
4)res:存放返回addrinfo构造链表的指针;
头文件:
#include <sys/types.h>#include <sys/socket.h>#include <netdb.h> void freeaddrinfo(struct addrinfo res);const char gai_strerror(int errcode); struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; socklen_t ai_addrlen; struct sockaddr ai_addr; char ai_canonname; struct addrinfo ai_next; }
参数解释:
在getaddrinfo函数之前常日须要对以下6个参数进行以下设置:nodename、servname、hints的ai_flags、ai_family、ai_socktype、ai_protocol。在6项参数中,对函数影响最大的是nodename,sername和hints.ai_flag。而ai_family只是有地址为v4地址或v6地址的差异。而ai_protocol一样平常是为0不作改动。
个中ai_flags、ai_family、ai_socktype解释如下:
参数
取值
值
解释
ai_family
AF_INET
2
IPv4
AF_INET6
23
IPV6
AF_UNSPEC
0
协议无关
—-
—-
—
—-
ai_protocol
IPPROTO_IP
0
IP协议
IPPROTO_IPv4
4
IPv4
IPPROTO_IPv6
41
IPv6
IPPROTO_UDP
17
UDP
IPPROTO_TCP
6
TCP
—-
—-
—
—
ai_socktype
SOCK_STREAM
1
流
SOCK_DGRAM
2
数据报
—-
—-
—
—
ai_flags
AI_PASSIVE
1
被动的,用于bind,常日用于 server socket
AI_CANONNAME
2
AI_NUMERICHOST
4
地址为数字串
对付ai_flags值的解释:
AI_PASSIVE
AI_CANONNAME
AI_NUMERICHOST
0/1
0/1
0/1
如上表所示,ai_flagsde值范围为0~7,取决于程序如何设置3个标志位,比如设置ai_flags为 “AI_PASSIVE|AI_CANONNAME”,ai_flags值就为3。
三个参数的含义分别为:
(1)AI_PASSIVE 当此标志置位时,表示调用者将在bind()函数调用中利用返回的地址构造。当此标志不置位时,表示将在connect()函数调用中利用。当节点名为NULL,且此标志置位,则返回的地址将是通配地址。如果节点名为NULL,且此标志不置位,则返回的地址将是回环地址。
(2)AI_CANNONAME当此标志置位时,在函数所返回的第一个addrinfo构造中的ai_cannoname成员中,该当包含一个以空字符结尾的字符串,字符串的内容是节点名的正规名。
(3)AI_NUMERICHOST当此标志置位时,此标志表示调用中的节点名必须是一个数字地址字符串。
给定host和service(套接字地址的两个组成部分),getaddrinfo返回result, result是一个指向addrinfo构造的链表,个中每个构造体指向一个对应于host和service的套接字地址构造。
在客户端调用了getaddrinfo之后,会遍历这个列表,一次考试测验每一个套接字地址,直到调用socket和connect成功,建立起连接。类似地,做事器会考试测验遍历列表中的每一个套接字的地址,直到调用socket和bind成功,描述符会被绑定到一个合法的套接字地址。为了避免内存泄露,运用程序必须调用freeaddrinfo,开释该链表。如果getaddrinfo返回非零的缺点代码,运用程序可以调用gai_streeror,将代码转成串。
getaddrinfo的host参数可以是域名,也可以是数字地址(如点分十进制IP地址)。service参数可以是做事名(如http),也可以是十进制端口号。如果不想把主机名转换成地址,可以把host设置为NULL。对service来说也是一样。但是必须指定两者中至少一个。
getaddrinfo一个很好的方面是addrinfo构造中的字段是不透明的,即它们可以直接通报给套接字接口中的函数,应程序代码无需再做任何处理。例如,ai_family、ai_socktype和ai_protocol可以直接通报给socket。类似的,ai_addr和ai_addrlen可以直接通报给connect和bind。这个强大的属性使得我们编写客户端和做事器能够独立于某一个分外版本的IP协议。
4.关于上面几个函数线程安全如下表所示:gethostbyname处理数据时返回的结果是存储在一个静态构造体变量中的,作为本地的一个全局变量,只初始化一次,也便是说,下次对这个变量进行操作时,是基于这次的结果来操作的。
下面小例子解释这个问题:
ht1 = gethostbyname(“www.sohu.com”);ht2 = gethostbyname(“www.baidu.com”); printf("ip:%s\n",inet_ntop(ht1->h_addrtype,ht1->h_addr_list[i],str,30));printf(":%s\n",ht1->h_aliases[i]); printf("IP:%s\n",inet_ntop(ht2->h_addrtype,ht2->h_addr_list[i],str,30));printf("alias:%s\n",ht2->h_aliases[i]);
ht1和ht2这个构造体指针在运行gethostbyname这个函数后指向的是同一个地址(即上面gethostbyname存储返回结果的变量地址)(大家可以在编译器里分部实行查看变量值的变革)
5.小结运用程序用来把主机名转换成IP地址,gethostbyname是曾常常用的入口。随着向IPv6和线程化编程模型的转移,getaddrinfo显得更有用,由于它既解析IPv6地址,又符合线程安全。