Mudo C++網路庫第六章學習筆記
self發表於2018-10-23
muduo網路庫簡介
- 高階語言(Java, Python等)的Sockects庫並沒有對Sockects API提供更高層的封裝, 直接用它編寫程式很容易掉到陷阱中;
- 網路庫的價值還在於能方便地處理併發連結;
網路核心庫
- muduo是基於Reactor模式的網路庫, 其核心是個事件迴圈EventLoop,用於響應計時器和IO事件;
- muduo採用基於物件(object-based)而非物件導向(object-oriented)的設計風格;
網路附屬庫
- 網路庫有一些附屬模組, 它們不是核心內容, 在使用的時候需要連結相應的庫;
- 使用muduo庫而言, 只需要掌握5個關鍵類:Buffer,EventLoop, TcpConnection, TcpClient, TcpServer;
執行緒模型
- muduo的執行緒模型符合one loop per thread + thread pool模型;
- 每個執行緒最多有一個EventLoop, 每個TcpConnection必須歸某個EventLoop管理, 所有的IO會轉移到這個執行緒;
- ThreadPool, 新到的連結會按round-robin方式分配到執行緒池中;
- muduo庫的核心是每個IO執行緒一個事件迴圈, 把IO事件分發到回撥函式上;
- 希望muduo庫能減少網路程式設計中的偶發複雜性(accidental complexity);
- 基於事件的非阻塞網路程式設計是編寫高效能併發網路服務程式的主流模式;
- TCP網路程式設計最本質是處理三個半事件:
- 連線的建立, 包括伺服器端接受(accept)新連結和客戶端成功發起(connect)連結; TCP連線一旦建立, 客戶端和服務端是平等的, 可以各自收發資料;
- 連線的斷開, 包括主動斷開(close, shutdown)和被動斷開(read返回0);
- 訊息到達, 檔案描述符可讀; 這是最重要的一個事件, 對它的處理方式決定了網路程式設計的風格(阻塞還是非阻塞, 如何處理分包, 應用層的緩衝如何設計, 等等);
- 訊息傳送完畢, 這個算半個; 對於低流量的服務, 可以不必關心這個事件; 另外, 這裡的傳送完畢是指資料寫入作業系統的緩衝區, 將由TCP協議棧負責資料的傳送與重傳, 不代表對方已經收到了資料;
- echo 伺服器的實現:
- muduo的使用非常簡單, 不需要從指定的類派生, 也不用覆寫虛擬函式, 只需要註冊幾個回撥函式去處理三個半事件就行了;
- echo伺服器的業務邏輯就是把收到的資料原封不動地發回客戶端;
- 程式主體是被動等待事件發生, 事件發生之後網路庫會呼叫(回撥)事先註冊的事件處理函式(event handler);
- 七步實現finger服務
- Python Twisted是一款非常好的網路庫, 它也是採用的Reactor作為網路程式設計的基本模型, 所以從使用上與muduo頗有相似之處(muduo沒有deferreds);
- finger是Twisted文件中一個經典的例子, muduo來實現最簡單的finger服務端;
- 大佬的muduo學習筆記;
- finger(埠79)是互連網上最古老的協議之一, 用於提供站點及使用者的基本資訊, 一般通過finger服務,你可以查詢到站點上的線上使用者清單及其他一些有用的資訊;
- finger服務是基於客戶/伺服器模式的,目標機上通常有一個fingerd的伺服器程式(在unix中,被稱為finger守護程式);
- 而finger返回的結果是由這個程式決定的,使用或自己編些不同的程式,可以提供各種各樣的finger服務;
- 效能評測
- 在muduo庫擅長的領域(TCP長連線), 其效能不比任何開源網路庫差;
- muduo最開始並沒有以高併發、高吞吐為主要目標;
- ping pong 測試表明:
- muduo的吞吐量比Boost.Asio高15%;
- muduo的吞吐量比libevnet2高18%;
- muduo與Nginx的吞吐量對比
- 對比內建的簡陋的HTTP伺服器的長連線效能;
- 直接返回記憶體中的資料, 比較程式的網路效能;
- qps(每秒請求數)都能超過10萬;
- muduo與ZeroMQ的延遲對比;
- 詳解muduo庫多執行緒模型
- 以一個sudoku solver為例, 一個求解數獨的伺服器程式;
- 從網路連線讀入一個sudoku題目, 算出答案, 再發回給客戶端;
- 怎麼做才能發揮多核硬體的能力;
- 一個簡單的以'\r\n'分隔的文字行協議, 使用TCP長連線, 客戶端在不需要服務時主動斷開連線;
- 正確使用non-blocking IO需要考慮的問題很多, 不適宜直接呼叫Sockect API, 而需要一個功能完善的網路庫支撐;
- 目前高效能httpd普遍採用的是單執行緒Reactor方式;
- reactors+thread pool是最靈活的IO與CPU配置;
- 通常由網路庫負責讀寫socket, 使用者程式碼負責解碼、計算和編碼;
- C++多執行緒伺服器程式設計模式為: one loop per thread + thread pool
- event loop 用作non-blocking IO 和定時器;
- thread pool用來做計算, 具體可以是任務佇列或生產者消費者佇列;