TCP IP Socket In C, 2e - chapter 3 Of Names and Address Families

本文其实是在说DNS的东西,以及如何运行时判断使用IPv4还是IPv6。

1. 名字和数字(IP地址)的映射

人类记忆字符比记忆一串数字要更加在行,而且IP地址可能随着ISP的更改而在变化,所以使用一种称为“名字系统”(Name System)以完成名字和数字之间的映射就成了势在必行的东西。这便是DNS(Domain Name System)协议。

这里主要使用到3个函数。

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
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():one or more addrinfo structures,这个是由双重指针results指向
 * @params: 
 * 	hostStr: Internet host
 * 	serviceStr: a service
 * 	hints: specifies criteria, tells the system what kinds of endpoints the caller is interested in
 *  results:
 * @return:
 * 	成功返回0
 * 	失败返回非0值
 * 	
 */
int getaddrinfo(const char *hostStr, const char *serviceStr, 
				const struct addrinfo *hints, struct addrinfo **results);
			
/*
 * freeaddrinfo(): 释放的是getaddrinfo返回的results参数所指向的。
 * @params:
 * 	addrList: 就是上一个的*results
 * @return:
 */	
void freeaddrinfo(struct addrinfo *addrList);

/*
 * gai_strerror(): 把返回的int数字转为对应的错误信息
 * @params:
 * 	errorCode: 是getaddrinfo返回
 * @return:
 */
const char *gai_strerror(int errorCode);

其中,getaddrinfo()函数第四个参数是一个二重指针,是一个链表形式的。因为对于一个域名来说,可能有多个IP地址或服务类型,如IPv4TCP、IPv6UDP,需要一一列举出来。

这里有一个使用上述函数的例子GetAddrInfo.c,这个函数还使用了Practical.hDieWithMessage.c以及AddressUtility.c中的PrintSocketAddress()方法。编译的时候请注意。

2. 通用地址程序

Socket API允许我们把确定用IPv4还是IPv6地址的决定推迟到运行时来做。

最重要的其实是使用getaddrinfo()传参hints时,把ai_family设置为AF_UNSPEC。这样就能够既接收IPv4又接收IPv6地址了。

这里使用到的程序是Practical.hTCPEchoClient.cTCPEchoServer.cTCPClientUtility.cTCPServerUtility.cDieWithMessage.cAddressUtility.c

3. 从数字(IP地址)获取名字

其实这个是getaddrinfo()的反着用,从IP地址得到对应的名字,不过使用的是函数getnameinfo(),而且它的行为和getaddrinfo()基本一致,返回值为0则成功,非0也可以传递给gai_strerror()以获取对应的错误信息。

/*
 * getnameinfo: the inverse of getaddrinfo(3): it converts a socket address 
 * 		to a corresponding host and service, in a protocol-independent manner.
 * 		【通过socket地址同时获得以字符串表示的主机名和服务名】
 * @params:
 * 	addr: 地址
 * 	addrlen: 	地址长度
 * 	host: 		保存返回的主机名
 * 	hostlen: 	主机名长度
 * 	serv: 		保存返回的服务名
 * 	servlen: 	服务名长度
 * 	flags:
 * @return:
 * 	同getaddrinfo()
 */
int getnameinfo(const struct sockaddr *addr, socklen_t addrlen,
                char *host, socklen_t hostlen,
                char *serv, socklen_t servlen, int flags);

有关这些函数的详细内容,可以使用Man Pages查看,也可以参考Linux下C Socket编程基础API。尤其注意struct addrinfoai_flags的设置以及getnameinfo()中的flags的设置,二者都可以使用位或操作符|

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章