找出全書你認爲最重要的一章,深刻從新學習一下,要求(期末佔10分):html
完成這一章全部習題java
詳細總結本章要點git
給你的結對學習搭檔講解你的總結並獲取反饋程序員
咱們須要理解基本的客戶端-服務端編程模型,以及如何編寫使用因特網提供的服務的客戶端-服務端程序。web
最後,咱們將把全部這些概念結合起來,開發一個小的但功能齊全的Web服務器,可以爲真實的Web瀏覽器提供靜態的和動態的文本和圖形內容。編程
每一個網絡應用程序都是基於客戶端 - 服務器模型的,
採用這種模型,一個應用是由一個服務器進程 和一個或多個客戶端進程組成。瀏覽器
服務器管理某種資源,而且經過操做這種資源爲它的客戶端提供某種服務。安全
客戶端收到響應並處理它。服務器
客戶端
和服務端
一般運行在不一樣的主機上,而且經過計算機網絡
的硬件和軟件資源來通訊。網絡
網絡
只是又一種I/O
設備,做爲數據源和數據接收方。對於物理上而言,網絡是一個按照地理遠近組成的層次系統。
一個以太網段(Ethernet segment)包括一些電纜(一般是雙絞線)和一個叫作集線器的小盒子.
每一個以太網適配器(網卡)都有一個全球惟一的48位地址,它存儲在這個適配器的ROM上(MAC)。
使用一些電纜和叫作網橋(bridge)的小盒子,多個以太網段能夠鏈接稱較大的局域網,稱爲橋接以太網(bridged Ethernet)
一些電纜鏈接網橋與網橋,或者 網橋與集線器。
這些電纜的帶寬能夠是不一樣的。
在層次的更高級別,多個不兼容的局域網能夠經過叫作路由器(router)的特殊計算機鏈接起來,組成一個internet(互聯網絡)
Internet和internet
咱們老是用小寫字母的internet表示通常概念,大寫的Internet表示一種具體實現,如全球IP因特網。
WAN(Wide-Area Network,廣域網)
互聯網相當重要的特性是:
它能由採用徹底不一樣和不兼容技術的各類局域網和廣域網組成。
Q:如何可以讓某臺源主機跨過全部這些不兼容的網絡發送數據位到另外一臺目的主機呢?
A:解決辦法是一層運行在每臺主機和路由器上的協議軟件,消除不一樣網絡之間的差別。
這個軟件實現一種協議:控制主機和路由器如何協調工做來實現數據傳輸。
必須提供兩種基本能力:
命名機制
每臺主機會被分配至少一個互聯網地址(internet address),這個地址惟一標識了這臺主機。
傳送機制
協議經過定義一種把數據位捆紮成不連續的片(稱爲包)的方式。
一個包是由包頭和有效載荷組成的。
包頭
包的大小
源主機和目的主機地址
有效載荷包括從源主機發出的數據位.
每臺因特網主機都運行實現TCP/IP協議 (Transmission Control Protocol/Intelnet Protocol,傳輸控制協議/互聯網絡協議)的軟件,幾乎全部計算機系統都支持這個協議
TCP/IP協議實際上一個協議族,每個協議提供不一樣的功能。
從程序員的角度,咱們能夠把因特網看做世界範圍內主機的集合,知足一下特性。
inet_aton
和inet_ntoa
函數來實現二者之間互相轉換。因特網域名
葉子結點反向到根的路徑就是域名。
層次結構第一層 : 未命名的根結點
層次結構第二層 : 一級域名(first-level domain name)
由非盈利組織ICANN(Internet Corporation for Assigned Names and Numbers,因特爾分配名字數字協會)定義。
常見的一級域名:com,edu,gov,org和net。
層次結構第三層: 二級域名(second-level)
例如:cmu.edu。
套接字接口(socket interface)是一組函數,他們和Unix I/O函數結合起來,用以建立網絡應用。
給出一個典型的客戶端-服務器事務的上下文中套接字接口概述,以此導向。
sin_family成員是AF_INET,ipv4仍是ipv6。
sin_port成員是一個16位的端口號。
sin_addr成員就是一個32位的IP地址。
IP地址和端口號老是以網絡字節順序(大端法)存放的。
sockaddr_in給程序員操做的,sockaddr交由套接字函數使用的,二者能夠直接強制轉換。
11.7
在get_filetype函數裏面添加:
else if(strstr(filename, ".mpg") || strstr(filename, ".mp4"))
strcpy(filetype, "video/mpg");
11.8
結束子進程以前,咱們不能夠關閉已鏈接描述符。這就致使咱們仍是得讓serve_dynamic或者是doit函數或者main函數中要等待子進程結束。迭代服務器的設計讓這個問題變得比較無聊。
在main函數以前加入代碼:
int chdEnded ; #include <signal.h> void child_signal(int sig) { pid_t pid; while((pid = waitpid(-1, NULL, WNOHANG)) > 0) ; chdEnded = 1; }
在main函數中添加語句 signal(SIGCHILD, child_handle);
每次accept以前,讓chdEnded = 0;
而且在doit()中的serve_dynamic以後添加:
while(!chdEnded) pause();//or do sth
刪掉serve_dynamic裏的wait(NULL);
11.9
serve_static中的存儲器映射語句改成:
srcfd = open(filename, O_RDONLY, 0);
srcp = (char)malloc(sizeof(char)filesize);
rio_readn(srcfd, srcp, filesize);
close(srcfd);
rio_writen(fd, srcp, filesize);
free(srcp);
11.10
HTML文件:
<html> <body> <form name="input" action="cgi-bin/adder" method="get"> Num1: <input type="text" name="num1"/> <br/> Num2: <input type="text" name="num2"/> <br/> <input type="submit" value="Submit"/> </form> </body> </html> 由於提交的表單裏面有參數名字(num1=x&num2=y),因此要修改相應的adder.c: int parseNum(char *s) { int i = strlen(s) - 1; while(i>0 && s[i-1]>='0'&&s[i-1]<='9' ) i--; return atoi(s+i); } int main(void) { char *buf, *p; char arg1[MAXLINE], arg2[MAXLINE], content[MAXLINE]; int n1=0, n2=0; /* Extract the two arguments */ if ((buf = getenv("QUERY_STRING")) != NULL) { p = strchr(buf, '&'); *p = 0; strcpy(arg1, buf); strcpy(arg2, p+1); n1 = parseNum(arg1); n2 = parseNum(arg2); } /* Make the response body */ sprintf(content, "Welcome to add.com: "); sprintf(content, "%sTHE Internet addition portal.\r\n<p>", content); sprintf(content, "%sThe answer is: %d + %d = %d\r\n<p>", content, n1, n2, n1 + n2); sprintf(content, "%sThanks for visiting!\r\n", content); /* Generate the HTTP response */ printf("Content-length: %d\r\n", (int)strlen(content)); printf("Content-type: text/html\r\n\r\n"); printf("%s", content); fflush(stdout); exit(0); }
11.11
想到的辦法就是定義一個變量rmtd,表示請求的方法。
在client_error,serve_static和serve_dynamic中添加一個參數mtd(改的地方也比較多),表示方法。若是mtd爲HEAD,就只打印頭部。
11.12
仍是使用rmtd表示方法。
這裏須要改的還有讀取報頭。
用POST方法,表單的參數是在報頭以後。
報頭中有一項是Content-Length,讀取出來,在報頭讀完以後,接着讀取Content-Length個字節(注意最後添0),這些字節就是form用post方法提交的數據。
主要修改的就是doit方法和read_request方法。
下面的程序只能針對參數爲文本的狀況,且參數總長度最大不超過MAXLINE。
#define M_GET 0 #define M_POST 1 #define M_HEAD 2 #define M_NONE (-1) void doit(int fd) { int is_static; int rmtd = 0; struct stat sbuf; char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE]; char filename[MAXLINE], cgiargs[MAXLINE]; rio_t rio; /*for post*/ int contentLen; char post_content[MAXLINE]; /* Read request line and headers */ rio_readinitb(&rio, fd); rio_readlineb(&rio, buf, MAXLINE); sscanf(buf, "%s %s %s", method, uri, version); printf("%s %s %s\n", method, uri, version); if(strcmp(method, "GET") == 0) rmtd = M_GET; else if(strcmp(method, "POST") == 0) rmtd = M_POST; else if(strcmp(method, "HEAD") == 0) rmtd = M_HEAD; else rmtd = M_NONE; if (rmtd == M_NONE) { clienterror(fd, method, "501", "Not Implemented", "Tiny does not implement this method", rmtd); return; } contentLen = read_requesthdrs(&rio, post_content, rmtd); /* Parse URI from GET request */ is_static = parse_uri(uri, filename, cgiargs); if (stat(filename, &sbuf) < 0) { clienterror(fd, filename, "404", "Not found", "Tiny couldn't find this file", rmtd); return; } if (is_static) {/* Serve static content */ if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) { clienterror(fd, filename, "403", "Forbidden", "Tiny couldn't read the file", rmtd); return; } serve_static(fd, filename, sbuf.st_size, rmtd); } else {/* Serve dynamic content */ if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) { clienterror(fd, filename, "403", "Forbidden", "Tiny couldn't run the CGI program", rmtd); return; } if(rmtd == M_POST) strcpy(cgiargs, post_content); serve_dynamic(fd, filename, cgiargs, rmtd); }
}
int read_requesthdrs(rio_t *rp, char* content, int rmtd) { char buf[MAXLINE]; int contentLength = 0; char *begin; rio_readlineb(rp, buf, MAXLINE); while(strcmp(buf, "\r\n")) { rio_readlineb(rp, buf, MAXLINE); printf("%s", buf); if(rmtd == M_POST && strstr(buf, "Content-Length: ")==buf) contentLength = atoi(buf+strlen("Content-Length: ")); } if(rmtd == M_POST){ contentLength = rio_readnb(rp, content, contentLength); content[contentLength] = 0; printf("POST_CONTENT: %s\n", content); } return contentLength; }
2.有關Web服務器的說法,正確的是()
錯誤緣由
我選了ACD,沒有選B.課本上P666頁寫,可執行文件的URL能夠在文件名後包括程序參數。「?」字符分隔文件名和參數,並且每一個參數都用「&」隔開。課本沒有說這兩個參數是可執行文件產生的,因此我沒有選。
查閱資料後,這兩個參數確實是由可執行文件產生的,因此答案爲ABCD。
9.如圖關於struct sockaddr_in和struct sockaddr,下面說法正確的是()
D .套接字接口中的地址類型是sturct sockaddr_in
我選的是ABC,答案是AC。
對於A選項,AF_INET(又稱 PF_INET)是 IPv4 網絡協議的套接字類型,AF_INET6 則是 IPv6 的;而 AF_UNIX 則是 Unix 系統本地通訊。因此A是對的。
對於B選項,sin_family參數指定調用者期待返回的套接口地址結構的類型。它的值包括三種:AF_INET,AF_INET6和AF_UNSPEC。若是指定AF_INET,那麼函數就不能返回任何IPV6相關的地址信息;若是僅指定了AF_INET6,則就不能返回任何IPV4地址信息。AF_UNSPEC則意味着函數返回的是適用於指定主機名和服務名且適合任何協議族的地址。
故B錯誤。
對於C ,課本P653頁有,因此C選項是正確的。
10.有關Socket端口和Linux命令,下面說法正確的是()
F .ps -aux | grep pid 能夠查看綁定某端口的進程號爲pid的進程的詳細狀況
我選的是BCEF,正確答案:ABCDEF
我在終端輸入這些命令,eco /etc/services沒有顯示端口狀況。
lsof -i:80也沒有任何輸出。因此選錯了。
因此我很疑惑,但願老師可以解答。
11.知名端口號(well-known port numbers)就是那些由互聯網名稱與數字地址分配機構(ICANN)預留給傳輸控制協議(TCP)和用戶數據包協議(UDP)使用的端口號。下面有關知名端口號的說法正確的是()
K .auth服務的端口號是113
正確答案:ACDFGHIJK
B選項,FTP的端口號是20和21
E選項,telnet的端口號是23
18( 多選題 | 1 分)
有關域名和IP地址的說法,正確的是()
A .
1988年前,域名和IP地址的映射經過HOST.txt來完成
B .
1988年後,域名和IP地址的映射經過DNS來完成
C .
Linux中可使用hostname(1)來展現和某個IP對應的域名
D .
域名和IP地址的映射必須是1對1 的
我選的是ABC
對於C選項,hostname只能顯示或者設置主機名,不能展現某個IP對應的域名。
對於D選項,在最簡單的狀況下,域名和IP是一一對應的。可是,一個域名能夠對應多個IP,一個ip也能夠對應多個域名。
因此正確答案爲AB。
20155324博客中值得學習的或問題:
他學習的是第八章,異常處理其餘
- [20155324](http://www.cnblogs.com/wang5324/p/8053264.html) - 結對照片 - 結對學習內容 - 理解信號機制 - 掌握管道和I/O重定向
xxx
xxx
代碼行數(新增/累積) | 博客量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 |
| 第十四周 | 300/5000 | 2/25 | 15/300 | |
嘗試一下記錄「計劃學習時間」和「實際學習時間」,到期末看看能不能改進本身的計劃能力。這個工做學習中很重要,也頗有用。
耗時估計的公式
:Y=X+X/N ,Y=X-X/N,訓練次數多了,X、Y就接近了。
計劃學習時間:XX小時
實際學習時間:XX小時
改進狀況:
(有空多看看現代軟件工程 課件
軟件工程師能力自我評價表)