§有關(guān)電子資料鏈接:
http://www.unpbook.com/
§1.1 介紹

圖?1.2 服務(wù)器同時(shí)處理多個(gè)客戶端


§1.2 代碼示例和解說
1 #include? "unp.h"
2 int
3 main(int argc, char **argv)
4 {
5???? int???? sockfd, n;
6???? char??? recvline[MAXLINE + 1];
7???? struct sockaddr_in servaddr;
8???? if (argc != 2)
9???????? err_quit("usage: a.out <IPaddress>");
10???? if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
11???????? err_sys("socket error");
12???? bzero(&servaddr, sizeof(servaddr));
13???? servaddr.sin_family = AF_INET;
14???? servaddr.sin_port = htons(13);? /* daytime server */
15???? if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
16???????? err_quit("inet_pton error for %s", argv[1]);
17???? if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)
18???????? err_sys("connect error");
19???? while ( (n = read(sockfd, recvline, MAXLINE)) > 0) {
20???????? recvline[n] = 0;??????? /* null terminate */
21???????? if (fputs(recvline, stdout) == EOF)
22???????????? err_sys("fputs error");
23???? }
24???? if (n < 0)
25???????? err_sys("read error");
26???? exit(0);
27 }
其中unp.h是自定義的頭文件,查看源代碼。我們編譯并執(zhí)行以上代碼,得到以下輸出結(jié)果:
solaris %a.out 206.168.112.96???? our input | |
Mon May 26 20:58:40 2003??????????the program's output | |
下面簡要分析以上27行代碼,后續(xù)章節(jié)中有更詳細(xì)的討論.
包含我們自己的頭文件
1 該頭文件包含了大多數(shù)網(wǎng)絡(luò)程序所需要的多個(gè)頭文件以及定義了我們將要使用的一些常量(例如 MAXLINE).
命令行參數(shù)
2–3 這是含有命令行參數(shù)的主函數(shù)定義(即main函數(shù)).我們以ANSI C標(biāo)準(zhǔn)來書寫代碼.
創(chuàng)建TCP套接字
10–11 socket函數(shù)調(diào)用創(chuàng)建了一個(gè)網(wǎng)絡(luò)流套接字.(Internet (AF_INET) stream (SOCK_STREAM) socket), 該函數(shù)返回一個(gè)整數(shù)值,它描述了該套接字,以后的函數(shù)通過該整數(shù)值來使用這個(gè)套接字(例如connect和read等調(diào)用). 其中err_開頭的函數(shù)是我們自定義的函數(shù),詳見這里.
確定服務(wù)器IP地址和端口號
12–16 我們填充了網(wǎng)絡(luò)套接字地址結(jié)構(gòu)(一個(gè)名為servaddr的結(jié)構(gòu)體sockaddr_in),填充的信息包括服務(wù)器IP地址和端口號.我們把整個(gè)結(jié)構(gòu)體首先清零,然后設(shè)置地址族為AF_INET(IPV6該項(xiàng)為AF_INET6),端口號為13(時(shí)間服務(wù)器的端口號,是一個(gè)大家都知道的端口號).IP地址由命令行參數(shù)指定(argv[1]).IP地址和端口號必須按照指定的格式來填充,我們通過調(diào)用htons(主機(jī)字節(jié)流到網(wǎng)絡(luò)字節(jié)流的轉(zhuǎn)換)和inet_pton(點(diǎn)分十進(jìn)制到32位整數(shù)的轉(zhuǎn)換)兩個(gè)調(diào)用來進(jìn)行轉(zhuǎn)化到所需要的格式.
在調(diào)用inet_pton的時(shí)候可而能會遇到問題,因?yàn)檫@是IPv6新增的函數(shù),以前的IPv4版本可以調(diào)用inet_addr來替代該函數(shù).
與服務(wù)器建立一個(gè)連接
17–18 TCP套接字調(diào)用connect函數(shù),就與服務(wù)器(main函數(shù)的第二個(gè)參數(shù))建立了一個(gè)TCP連接,我們必須指定套接字結(jié)構(gòu)體的第三個(gè)參數(shù)長度,它總是讓編譯器通過C的sizeof運(yùn)算符來計(jì)算.
讀取和顯示服務(wù)器的回復(fù)
19–25 調(diào)用read來讀取服務(wù)器的回復(fù),利用標(biāo)準(zhǔn)I/O來顯示該回復(fù)信息.此外,在使用TCP的時(shí)候我們必須要注意,因?yàn)樗且粋€(gè)沒有邊界的字節(jié)流協(xié)議.服務(wù)器的回復(fù)是一個(gè)26字節(jié)的串:
Mon May 26 20 : 58 : 40 2003\r\n
\r 是回車, \n 是換行.
終止程序
26 exit 終止程序.Unix在一個(gè)進(jìn)程結(jié)束時(shí)候總是關(guān)閉所有打開的描述符,因此我們的TCP套接字此時(shí)關(guān)閉了.
后續(xù)內(nèi)容將對此有更深入的討論.