5.調用/捕獲系統函數
這部分我們使用系統的函數來訪問網絡他們在Unix的頭文件裡,以及任何支持套接字APP的操作系統(BSD、Windows、Linux、Mac等等)。當你調用他們中間的函數時,內核會自動幫助完成所有工作。
大多數就卡在這些系統函數裡。在這兒,因為你可能發現沒有可用的man!好,為了幫助順利適應它,我按照你的程序調用系統函數的順序來講解他們。
那麼,你需要一些牛奶和餅干,再給你提供一些樣例代碼。其它的就是你的勇氣、高昂的勇氣!你會發現原來竟然是如此的快樂!
(請注意,為了代碼的簡潔,沒有包含錯誤檢查。在調用getaddrinfo()函數成功時會返回一個有效的鏈表(linked list)。有些程序使用原始的地址(properly addressed ---也可譯原型的地址)這也可以。)
5.1. getaddrinfo()---准備運行
這個是真正的默默無聞的函數,雖然它有沒多參數,但是實際用起來很簡單。它對於你建立一個地址結構起到了簡化的作用。
一個小小的歷史:它曾經是,你會使用所謂的gethostbyname ()的函數做DNS查找。然後你手工加載一些信息給結構SOCKADDR_IN ,並供你調用。
值得慶幸的是,這不再是必要的了。(如果你要編寫工作在IPv4和IPv6的代碼,使用上邊所說的,也是不可取的!)在這現代化的時代,你已經有了getaddrinfo()函數並為你封裝好了不少東西,其中包括DNS和服務名稱查找,除了你自己填寫所需要的結構!
讓我們一起來看看!
#include<sys/types.h>
#include<sys/socket.h>
#include<netdb.h>
intgetaddrinfo(const char *node, //e.g. www.example.comor IP
const char *service, //e.g. “http” or port number
const struct addrinfo *hints,
struct addrinfo **res);
在這個函數裡有3個輸入參數和1個作為返回值的指向鏈表的指針res。
入參node是要連接的主機名或者IP地址。
下一個入參service是端口號,比如“80”,或者其它特定的服務名稱像“http”
、“ftp”、“telnet”、“smtp”等等。
最後,入參hints指向一個你已經填寫好了的addrinfo結構。
下面的示例是服務器在你的主機IP地址和端口號3490監聽。請注意,他們沒有做任何實際的監聽或者網絡設置;它只是在設置了結構hints並且做了調用。
int status;
struct addrinfohints;
struct addrinfo*servinfo; // will point to theresults
memset(&hints,0, sizeof(hints)); // make sure thestruct is empty
hints.ai_family =AF_UNSPEC; // don’t care IPv4 orIPv6
hints.ai_socktype= SOCK_STREAM; // TCP stream sockets
hints.ai_flags =AI_PASSIVE; // fill in myIP for me
if ((status =getaddreinfo(NULL, “3049”,&hints, &servinfo)) != 0) {
fprintf(stderr, “getaddrinfo error: %s\n”,gai_strerror(status));
exit(1);
}
// servinfo nowpoints to a linked list of 1 or more struct addrinfos
// … do everythinguntil you don’t need servinfo anymore …
// … do everythinguntil you don’t need servinfo anymore …
freeaddrinfo(servinfo);// free the linked-list
請注意:因為ai_family設置為AF_UNSPEC所以達到了與版本無關。你也能設置專為IPv4或者IPv6工作以及其它的地址族。
此外你在這兒看到了AI_PASSIVE標志;他告訴getaddrinfo()復制本機地址給套接字結構。這很好,因為沒有硬編碼。
譯者注:上邊的情況通常使用在服務器端!
下邊說的就是客戶端的情況。
示例:連接到www.example.net的3049端口。
int status;
struct addrinfohints;
struct addrinfo *servinfo; // will point to the results
memset(&hints,0 sizeof(hints)); // make sure the structis empty
hints.ai_family =AF_UNSPEC; // don’t care IPv4 or IPv6
hints.ai_socktype= SOCK_STREAM; // TCP stream sockets
// get ready toconnect
status =getaddrinfo(www.example.net, “3049”, &hints, &servinfo);
// servinfo nowpoints to a linked list of 1 or more struct addrinfos
// etc.
我一直說servinfo是一個可以指向各種地址的指針。我們寫一個簡單的演示程序來顯示不同的地址信息。這個程序在命令行上打印出你指定主機的IP地址。
showip.c
所需頭文件列表:
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netdb.h>
#include<arpa/inet.h>
流程圖
正如您所看到的,代碼調用的getaddrinfo()來填寫由res指向的鏈表,然後我們可以遍歷列表以及打印在命令行上。
譯者注:測試IPv6失敗!請讀者自行查找國內可用的IPv6站點。
現在我們已經在控制之下,我們將使用getaddrinfo()得到的結果,我們要傳遞給其他socket函數,終於,建立我們的網絡連接!請繼續閱讀!
摘自 xiaobin_HLJ80的專欄