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的設置,二者都可以使用位或操作符|

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