查找主机名最基本的函数是gethostbyname,POSIX规范预警,可能会在将来的某个版本中撤销gethostbyname函数,虽然除非整个因特网改为IPv6它才有可能消失,不过还是鼓励在新的程序中使用getaddrinfo函数。
#include
struct hostent* gethostbyname( const char* hostname );
struct hostent
{
char* h_name; /* official (canonical) name of host */
char** h_aliases; /* pointer to array of pointers to alias names */
int h_addrtype; /* host address tpye: AF_INET */
int h_length; /* length of address:4 */
char** h_addr_list;/* ptr to array of ptrs with IPv4 addrs */
};
当它发生错误时,它不设置errno变量,而是设置全局整数变量h_errno,它定义在中,为下列常值之一:
. HOST_NOT_FOUND
. TRY_AGAIN
. NO_RECOVERY
. NO_DATA(等同于NO_ADDRESS)
如今,多数解析器提供名为hstrerror的函数,它以某个h_errno值作为唯一的参数,返回的是一个const char*指针,指向相应错误说明。
与gethostbyname相对的是gethostbyaddr:
#include
struct hostent* gethostbyaddr( const char* addr, socklen_t len, int family );
它返回一个hostent的结构体,实际上,通常我们只对其中的h_name感兴趣。
另外,addr参数实际上不是char*类型,而是一个指向存放IPv4地址的某个in_addr结构的指针,len参数是这个结构的大小,对于IPv4地址为4。family参数为AF_INET。
像主机一样,服务也是靠名字来认知的。也就是说,我们在程序代码中通过其名字而不是其端口号来指代一个服务,而且从名字到端口号的映射关系保存在一个文件中(通常是/etc/services),那么,即使端口号发生变动,我们需要修改的仅仅是/etc/services文件中的某一行,而不必重新编译。
getservbyname函数用于根据给定名字查找相应服务。
#include
struct servent* getservbyname(const char* servname, const char* protoname);
struct servent {
char* s_name; /* official service name */
char** s_aliases; /* alias list */
int s_port; /* port number, network-byte order */
char* s_proto; /* protocol to use */
};
这里服务名servname必须指定,如果同时指定了协议,那么指定服务必须有匹配的协议。有的因特网服务即用TCP又用UDP提供。而如果protoname未指定而servname指定的服务支持多个协议,那么返回哪个端口号取决于实现。
与之相对的函数则是getservbyport,用于根据端口号和可选协议查找相应服务。
#include
struct servent* getservbyname( int port, const char* protoname );
需要注意的一点是,这里的port必须为网络字节序,所以需要使用htons。
gethostbyname和gethostbyaddr这两个函数只支持IPv4。可解析IPv6地址的函数为getaddrinfo函数。它能够处理名字到地址及服务到端口这两种转换。
#include
int getaddrinfo( const char* hostname, const char* service, const struct addrinfo* hints, struct addrinfo** result );
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*/
};
其中的hostname参数是一个主机名或地址串,service参数是一个服务名或十进制端口号数串。
hint参数可以为一个空指针,也可以是一个指向某个addrinfo结构的指针,调用者在这个结构中填入关于期望返回的信息类型的暗示。hints中可以设置的成员有:
. ai_flags
. ai_family
. ai_socktype
. ai_protocol
其中ai_flags成员可用的标志值如下:
. AI_PASSIVE
. AI_CANONNAME
. AI_NUMERICHOST
. AI_NUMERICSERV
. AI_V4MAPPED
. AI_ALL
. AI_ADDRCONFIG
POSIX声称如果调用者指定AF_UNSPEC,那么getaddrinfo函数返回的是适用于指定主机名和服务名且适合任意协议族的地址。当有多个addrinfo结构返回时,这些结构的先后顺序没有保证,也就是说,我们并不能假定TCP服务总是先于UDP服务返回。在addrinfo结构中返回的信息可现成用于socket调用。
关于此函数的一些常见输入:
. 指定hostname和service。这是TCP或UDP客房进程调用getaddrinfo的常规输入。该调用返回后,TCP客户对返回的IP地址逐一调用socket和connect,直到有一个成功为止。
. 典型的服务器进程只指定service而不指定hostname,同时在hints结构中指定AI_PASSIVE标志。返回的套接口地址结构中应含有一个值INADDR_ANY(对于IPv4)或IN6ADDR_ANY_INIT(对IPv6)的IP地址。如果服务器想要malloc另一个套接口地址以从accept获取客户地址,那么可以使用返回的ai_addrlen值给出这个套接口地址结构的大小。
gai_strerror以getaddrinfo返回的非0错误为参数,给出其错误信息的名字和含义
#include
const char* gai_strerror( int error );
由getaddrinfo返回的所有存储窨都是动态获取的,这些存贮空间通过调用freeaddrinfo返还给系统。
#include
void freeaddrinfo( struct addrinfo* ai );
阅读(1813) | 评论(0) | 转发(0) |