《深刻理解計算機系統》第11章網絡編程linux
11.4.7主機和服務的轉換程序員
include "csapp.h"編程
int main(int argc, char **argv)
{
struct addrinfo p,listp,hints;
char buf[MAXLINE];
int rc,flags;windows
if (argc != 2) { fprintf(stderr, "usage: %s <domain name or dotted-decimal>\n", argv[0]); exit(0); } memset(&hints,0,sizeof(struct addrinfo)); hints.ai_family=AF_INET; hints.ai_socktype = SOCK_STREAM; if((rc = getaddrinfo(argv[1],NULL,&hints,&listp)) != 0) { fprintf(stderr,"getaddrinfo error : %s\n",gai_strerroe(rc)); exit(1); } exit(0);
}
c語言給main函數傳參。
有兩種傳參格式:數組
int main(int argc, char** argv)服務器
int main(int argc, char* argv[])網絡
argc 是指命令行輸入參數的個數,argv是一個字符數組(或者二重指針)用來存放多個字符串,每一個字符串就是一個參數。app
注意在命令行下運行命令,./a.out parameter1 parameter2,argc的值是 3,argv[0]是"./a.out",argv[1]是"parameter1",argv[2]是"parameter2"。dom
參數缺乏提示
stderr是linux裏的標準輸出(設備)文件,對應終端屏幕。socket
fprintf是用於文件操做。
原型:int fprintf(FILE stream,char format,[argument]);
功能:fprintf()函數根據指定的format(格式)發送信息(參數)到由stream(流)指定的文件.所以fprintf()可使得信息輸出到指定的文件。
即這裏將會在屏幕上提示「usage: argv[0]
同時退出程序,exit(0)是正常退出,代碼一切正常的時候的退出。
C語言中的fscanf和fprint函數
stderr和stdout詳細解說
學兩個單詞:usage <n.>慣用法,domain name域名,dotted-decimal點分十進制
memset
void memset(void s,int c,size_t n) 將已開闢內存空間 s 的首 n 個字節的值設爲值 c,即給內存賦值。
memset用法詳解
addrinfo結構體原型
這裏使用memset是將struct addrinfo hints整個結構清0,再選擇性設置一些字段。
將ai_family設置爲AF_INET能夠將套接字地址結構體列表所有限制爲IPV4。
ai_socktype設置爲SOCK_STREAM將列表限制爲只有一個addrinfo結構。 若是不限制默認會返回三個addrinfo結構,即將TCP、UDP、原始數據報三種套接字都返回了,在使用時,遍歷這個列表嘗試每一個類型的套接字地址,直到成功鏈接。
調用getaddrinfo函數,host參數由用戶輸入,能夠是域名也能夠是點分十進制的數字地址。service參數爲空,即不將服務名傳化成地址。同時將設置了ai_family和ai_socktype字段的hints傳入,用於對返回的套接字地址列表進行控制。
若是調用失敗,經過錯誤代碼打印錯誤消息字符串。並退出程序。
exit(1)是異常退出,在不該該出現的分枝,要求終止程序的時候就用exit(1)
設置getnameinfo的flags爲NI_NUMERICHOST,不會返回域名而是數字地址字符串
遍歷列表中的每個addrinfo結構體,對每一個結構體調用getnameinfo。不須要返回服務字段
freeaddrinfo釋放列表。
總結:在用C語言使用windows socket時,主機和服務的轉化須要程序員藉助其餘函數(好比pton,ntop)手動完成,而getaddrinfo和getnameinfo提供了更高級別、獨立於任何特殊地址格式的抽象。這也體現了計算機領域頗有名的一句話:任何問題均可以經過加一層抽象層來解決。
11.4.8套接字接口的輔助函數
open_clientfd創建與服務器的鏈接,該服務器運行在主機hostname上,並在端口port上監聽鏈接請求。
open_listenfd打開和返回一個監聽描述符,準備好在端口port上接收鏈接請求。
值得注意的是,經過這兩個輔助函數全部代碼都與任何版本的IP無關。
echo客戶端和服務器的示例
include "csapp.h"
int main(int argc, char **argv)
{
int clientfd;
char host, port, buf[MAXLINE];
rio_t rio;
if (argc != 3) { fprintf(stderr, "usage: %s <host> <port>\n", argv[0]); exit(0); } host = argv[1]; port = argv[2]; clientfd = Open_clientfd(host, port); Rio_readinitb(&rio, clientfd); while (Fgets(buf, MAXLINE, stdin) != NULL) { Rio_writen(clientfd, buf, strlen(buf)); Rio_readlineb(&rio, buf, MAXLINE); Fputs(buf, stdout); } Close(clientfd); exit(0);
}