再讀UNPv1 複習 實踐 小結

2021-09-06 08:48:05 字數 3035 閱讀 6497

前言:

這算是第二次系統地閱讀unpv1,正如副標題,不希望寫成書摘、縮寫版,盡量多寫寫個人體會和獲得的經驗,因此很多地方都會從全書的角度來說明,而不僅僅限於某個章節內部。

sctp、訊號驅動i/o、廣播和多播等內容不包括在內。

準備工作:

為了適應在命令列介面編寫**,我先進行了vim環境的配置和xshell的配置。在讀書過程中還學習了gdb除錯程式的方法(見這裡)。

(1)vim外掛程式搭建

從別人那裡拷貝現成的的.vimrc和外掛程式,分別放於/home/使用者名稱 和/home/使用者名稱/vim資料夾下就行了。

(2)xshell遠端登入

熱身:出錯處理和包裹函式

unp中的**風格有一點是使用包裹函式和作者編寫出錯處理庫相結合,這使得初學者可以把注意力集中在學習主幹**本身,而不是在初學階段就不得不對所用到的函式考慮出錯處理,同時這並不影響**的穩健型,仍然提供了出錯時的提示和處理功能。因此複習的第一步是從出錯處理開始,這是unp附錄d.3的內容,幾個錯誤處理函式按照錯誤的差異決定以abort()、exit(1)、還是return做結尾;而出錯資訊的處理有乙個使用了可變引數列表的函式來完成,它按照需要把出錯資訊傳遞給syslog或是標準錯誤輸出。

包裹函式根據其呼叫函式的出錯情況來呼叫出錯處理,並且把全域性變數errno預存,處理完再返回,防止其他程序覆蓋。

第一章 & 第二章 基礎知識

第一章第乙個程式daytimetcpcli.c,用127.0.0.1做測試時,需要有daytime服務。開啟方法:當然直接自己編寫乙個伺服器也行,原書的後文提供了相關**。

關於這些函式關係的比喻:「sokcet()是安裝**機,bind()為它指定乙個使用的號碼,connect()是向某個號碼的伺服器撥號。」

tcp狀態轉換圖很經典,結合這個圖可以對各個函式(bind、listen、connect、accept、close)作出的狀態轉換(阻塞時的狀態、返回時機等)有更好的理解。狀態可以用netstat -anp|grep <#port>來檢視,在後續的程式執行和除錯中使用這個命令能加深對狀態和其轉換的理解。

習題2.5回顧了mss和路徑mtu發現功能的關係,值得看一看。

第三章 & 第四章 常用函式與資料結構

通用套接字的意義:使用sockaddr的強制轉換可以使套接字函式能夠處理來自所有支援的任何協議族的套接字結構,這也是為什麼它們需要乙個這個結構的長度作為引數的原因。

unp提供readline的原因是read和write不能夠按行處理緩衝區。

socket()的參數列比較有意思,後兩個引數會相互限定,但是由於這個限制不是唯一的,不可能把三個引數簡化成兩個引數。這麼講比較抽象,請結合圖4-5來理解。

connect()的出錯:超時、不可達、拒絕(可達但是不提供請求的服務)。

bind()通常是伺服器需要進行而客戶不必進行的。事實上客戶限定的套接字是由核心決定,繫結非通配位址後,解復用由核心而不是程序完成。

listen()的backlog引數unp解釋的比較含混,準確的解釋可以在man裡看到,並與具體系統有關。

每個檔案或套接字都有乙個引用計數(對於python,任何物件都有),這也相對於後面對close()和shutdown()差異的解釋(前者引用計數-1,為0時關閉;後者直接關閉並傳送tcp連線終止訊息)。

第五章 基本tcp程式設計 & 第八章 基本udp套接字程式設計

編寫的c/s**的框架(包括後面的多程序伺服器)沒什麼好說的,但這章開始,訊號處理就成了大部分程式中不可缺少的部分,unp裡訊號方面主要處理的物件是殭屍程序、sigpipe、中斷、alarm計時器這幾種。把signal函式的簡化定義看懂還是要花點功夫的。這裡我做了個引申:#define和typedef的區別是?參考

第六章 i/o復用(select、poll、kqueue、epoll)& 第十六章 與非阻塞i/o

大多數unix提供了select和poll,freebsd提供了kqueue,linux提供了epoll。其實它們很相似,如果仔細閱讀了select的例子再去看後面三者,是非常好理解的。個人感覺它們相當於一種核心進行的「輪詢」(不同於使用者實現的輪詢,有著更高的效率和更低的開銷),我們設定了要關注的描述符(套接字、標準輸入輸出等)以及我們所關注的狀態(是可讀了、可寫了還是別的什麼的),或許還需要設定個flags,一旦出現了這個狀態就按我們預設的行為去操作,它們表面上的區別只是在於借助的輔助資料結構的不同。之前寫過epoll的**,可以參考這裡。

而對於unp的第十六章的非阻塞i/o,基本都是通過設定套接字為非阻塞模式並select來實現的。但是非阻塞i/o並沒有投入睡眠,而是反覆地進行系統呼叫(6.2 i/o模型)。

同時,6.4~6.6節非常繞口的解釋了為什麼stdio和select混合使用時非常容易犯錯誤的:對eof的處理會導致函式的退出,而這時傳送緩衝區可能還有內容要處理。

第七章 套接字選項 & 第十一章 名字位址轉換 & 第十四章 高階i/o函式

內容很多,但是沒必要一條一條記著,有需要再查就行。

第十一章提供的一些函式比較好用(tcp_listen等),可以作為自己以後用的庫函式。

第十三章 守護程序

編寫的daemon_init()可以守護程序化當前程序,值得加入函式庫。

第三十章  c/s設計正規化

這章比較綜合,將不同的c/s實現方式做了個綜合和比較,包含了迭代模型、程序模型、執行緒模型、簡單的程序/執行緒池(預先派生,任務分配和均衡由核心完成)、程序互斥方式(檔案鎖和執行緒鎖)、描述符傳遞(使用到了unix域套接字)等,並且還包含了程序使用的使用者/系統時間的測定,非常有價值,建議讀者把這部分**動手實現一下。

另外第十二章的ipv4/v6互操作性簡單讀了下。

在這次複習中,所看部分的大部分**都實現並除錯執行通過,並且按照unp原始碼的組織形式進行組織。最後是以乙個第二十八章的ping程式的學習和實現作為這次學習的結束。ping的原始碼在unp上很完善了,不必多言,如果需要不切換超級使用者就能執行,可以參考這篇博文。

再讀UNPv1 複習 實踐 小結

前言 這算是第二次系統地閱讀unpv1,正如副標題,不希望寫成書摘 縮寫版,盡量多寫寫個人體會和獲得的經驗,因此很多地方都會從全書的角度來說明,而不僅僅限於某個章節內部。sctp 訊號驅動i o 廣播和多播等內容不包括在內。準備工作 為了適應在命令列介面編寫 我先進行了vim環境的配置和xshell...

UNPv1第十八章 廣播

單播ip資料報僅有通過目的ip位址指定的單個主機接受,子網上的其他主機均不受影響 子網上所有未參加相應廣播應用的所有機也必須沿協議棧一路向上完整的處理收取udp廣播資料報,直至該資料報經歷udp層時被丟棄為止 include unp.h static void recvfrom alarm int ...

UNPv1第十三章 高階IO

涉及套接字上的i o操作設定超時的方法有三種方法 呼叫alarm,在到達指定時間時產生sigalrm訊號 使用select阻塞在等待i o上,select內部有乙個時間限制,以此代替在read或write呼叫上阻塞 使用新的so rcvtimeo和so sndtimeo套接字選項 前兩種技術可以用於...