UNP讀書筆記 第五章 回射程式的各種改進

2021-08-14 20:24:10 字數 2874 閱讀 9451

本章首先編寫了1個伺服器回射程式,1個客戶傳送程式。隨後根據各類問題,進行相應的改進。這裡記錄一下 改進的過程。

伺服器程式很簡單, 大概是以下幾步:

建立套接字->繫結位址結構->監聽

進入while迴圈, 做accpet等待連線建立->一旦連線建立成功, 返回乙個connecfd套接字,  並fork乙個子程序 

父程序關閉connecfd套接字,繼續進入accpet等待連線

子程序執行回射函式-> 回射函式是乙個while迴圈,不斷從客戶套接字中read對應的資料,並傳送回去。 當read返回<=0即輸入了eof或read出錯時, 退出迴圈,輸出報錯資訊

#include "unp.h"

void str_echo(int sockfd)

if(n < 0 && errno == eintr)

else if (n < 0)

}int main(int argc, char **argv)

close(connfd);

}}

客戶程式:

建立套接字->與要發往的伺服器位址進行connect

當connect返回時,說明連線建立成功,執行傳送函式

傳送函式是1個while迴圈。每次在標準輸入上fgets讀取一行,然後傳送給伺服器,

傳送之後readline伺服器上發回的資料,並輸出。

如果readline返回錯誤,則報錯。

#include "unp.h"

#include void str_cli(file *fp, int sockfd)

}int main(int argc, char **argv)

sockfd = socket(af_inet, sock_stream, 0);

bzero(&servaddr, sizeof(servaddr));

servaddr.sin_family = af_inet;

servaddr.sin_port = htons(serv_port);

inet_pton(af_inet, argv[1], &servaddr.sin_addr);

connect(sockfd, (sa *) &servaddr, sizeof(servaddr));

str_cli(stdin, sockfd);

exit(0);

}

正常終止:

當我們在客戶程序上輸入eof關閉(ctrl +d)時,fgets讀入空指標->退出while迴圈->退出函式->程式執行完畢,

程序關閉

->程序關閉時,自動關閉開啟的所有套接字,於是客戶tcp傳送fin給伺服器,進行四次揮手。

注意:連線中止後,通過netstat可以檢視到客戶套接字此時正處於timewait狀態,大概好幾秒之後才真正關閉。

存在的問題:伺服器子程序因為readline收到fin而退出,結束,但是父程序並沒有處理子程序結束的操作

所以,子程序變成了僵死程序,並沒有真正的被清除,其空間和副本被保留,如果忽略該處理,記憶體會被耗盡。

改進a——處理僵死程序:

在伺服器程序開啟監聽之後, 加入signal(sigchld,sig_chld),即程序開啟對「子程序終止」訊號的捕捉

一旦捕捉到,則執行sig_chld函式

sig_chld函式: 該函式中執行了wait函式,等待1個子程序返回,並**對應狀態資訊。

注意1:這個訊號的捕捉一定是父程序才能捕捉得到。

注意2:當該訊號捕捉到時,父程序正阻塞於accept上,此時執行了訊號中斷,於是accpet出錯

返回的錯誤是「中斷錯誤」

所以伺服器**中,在accpet返回的是錯誤且錯誤是中斷錯誤時, 要繼續執行while迴圈做accpet

而不是直接結束整個程序

存在的問題:當有多個子程序同時終止時,會在同一時間內產生多個sigchld訊號, 導致wait的接受存在不確定性

改進b——處理多個子程序終止的情況

在sig_chld訊號處理函式中, 加入while迴圈,並執行不阻塞的waitpid,用迴圈依次將死掉的子程序乙個個取出。

#include "unp.h"

void str_echo(int sockfd)

if(n < 0 && errno == eintr)

else if (n < 0) }

void sig_chld(int signo)

int main(int argc, char **argv)

if( (childpid = fork()) ==0)

close(connfd);

}}

存在的問題: 如果突然kill掉伺服器子程序, 雖然伺服器作為結束發起方,傳送了fin給客戶,客戶也回應了ack

但根據四次揮手的協議,客戶要發完要發的資料,才會傳送fin

這時候客戶阻塞在 讀取終端輸入上。只有當我們輸入字串,讓客戶端端傳送時,客戶才會收到伺服器發回的rst

然後才執行fin傳送。

這個問題應該由select和poll解決

伺服器的主機崩潰(類似於網路斷開,不是程序關閉)

此時客戶沒有收到fin等資訊,於是會不斷進行重傳,直到超時,相應目的地不可達。

伺服器主機崩潰後又重啟

此時程序已經在崩潰後不存在了,但是並沒有傳送fin等操作, 但主機上的tcp仍會收到客戶發來的tcp

此時會自動相應乙個rst

伺服器關機

關機與崩潰不同,關機時,會用init程序來關閉所有程序,並關閉所有描述符,使得客戶能夠檢測到。

傳送二進位制資料

可能會因為大小端不同,出現問題。

第五章 讀書筆記

第五章 搭建s3c6410開發板的測試環境 一.s3c6410開發板簡介.s3c6410是三星公司推出的一款低功耗,高價效比的risc處理器,它基於arm11核心,可廣泛應用於移動 和通用處理器等領域。該處理器有乙個非常先進的3d加速器,能實現4m s的3d加速 二.安裝串列埠除錯工具 minico...

C Template 讀書筆記 第五章

內容 技巧性基礎知識 關鍵字 typename template this 模板的模板引數 零初始化 字串的模板實參 具體內容描述 1.對模板使用typename 場景 template class test 這裡需要增加typename,需要標記告訴編譯器這個是宣告乙個模板引數型別t裡面的subt...

C 讀書筆記 第五章 語句

空語句 程式某處語法上需要一條語句而邏輯上不需要 建議使用時加注釋 while cin s s sought 空塊的作用等同於空語句 上面的 也可以用 代替 懸垂 else switch case關鍵字和它對應的值一起被稱為case標籤,case標籤必須是整形常量表示式 case 3.14 錯誤 不...