3dwoo大學簡體電腦書店
Linux多線程服務端編程:使用muduo C++網絡庫
( 簡體 字)
作者:陳碩類別:1. -> 作業系統 -> Linux
出版社:電子工業出版社Linux多線程服務端編程:使用muduo C++網絡庫 3dWoo書號: 54801
詢問書籍請說出此書號!
有庫存
NT售價: 640
出版日:4/1/2021
頁數:616
光碟數:0
站長推薦:
印刷:黑白印刷語系: ( 簡體 字 )
ISBN:9787121192821 加入購物車加到我的最愛 (請先登入會員)
(簡體書上所述之下載連結耗時費功, 恕不適用在台灣, 若讀者需要請自行嘗試, 恕不保證, 繁體書的下載亦請直接連絡出版社)
第 1 部分 C++ 多線程系統編程
第 1 章 線程安全的對象生命期管理
1.1 當析構函數遇到多線程
1.1.1 線程安全的定義
1.1.2 MutexLock 與 MutexLockGuard
1.1.3 一個線程安全的 Counter 示例
1.2 對象的創建很簡單
1.3 銷毀太難
1.3.1 mutex 不是辦法
1.3.2 作為數據成員的 mutex 不能保護析構
1.4 線程安全的 Observer 有多難
1.5 原始指針有何不妥
1.6 神器 shared_ptr/weak_ptr
1.7 插曲:系統地避免各種指針錯誤
1.8 應用到 Observer 上
1.9 再論 shared_ptr 的線程安全
1.10 shared_ptr 技術與陷阱
1.11 對象池
1.11.1 enable_shared_from_this
1.11.2 弱回調
1.12 替代方案
1.13 心得與小結
1.14 Observer 之謬
第 2 章 線程同步精要
2.1 互斥器(mutex)
2.1.1 只使用非遞歸的 mutex
2.1.2 死鎖
2.2 條件變量(condition variable)
2.3 不要用讀寫鎖和信號量
2.4 封裝 MutexLock、MutexLockGuard、Condition
2.5 線程安全的 Singleton 實現
2.6 sleep(3) 不是同步原語
2.7 歸納與總結
2.8 借 shared_ptr 實現 copy-on-write
第 3 章 多線程服務器的適用場合與常用編程模型
3.1 進程與線程
3.2 單線程服務器的常用編程模型
3.3 多線程服務器的常用編程模型
3.3.1 one loop per thread
3.3.2 線程池
3.3.3 推薦模式
3.4 進程間通信只用 TCP
3.5 多線程服務器的適用場合
3.5.1 必須用單線程的場合
3.5.2 單線程程序的優缺點
3.5.3 適用多線程程序的場景
3.6 “多線程服務器的適用場合”例釋與答疑
第 4 章 C++ 多線程系統編程精要
4.1 基本線程原語的選用
4.2 C/C++ 系統庫的線程安全性
4.3 Linux 上的線程標識
4.4 線程的創建與銷毀的守則
4.4.1 pthread_cancel 與 C++
4.4.2 exit(3) 在 C++ 中不是線程安全的
4.5 善用 __thread 關鍵字
4.6 多線程與 IO
4.7 用 RAII 包裝文件描述符
4.8 RAII 與 fork()
4.9 多線程與 fork()
4.10 多線程與 signal
4.11 Linux 新增系統調用的啟示
第 5 章 高效的多線程日志
5.1 功能需求
5.2 性能需求
5.3 多線程異步日志
5.4 其他方案
第 2 部分 muduo 網絡庫
第 6 章 muduo 網絡庫簡介
6.1 由來
6.2 安裝
6.3 目錄結構
6.3.1 代碼結構
6.3.2 例子
6.3.3 線程模型
6.4 使用教程
6.4.1 TCP 網絡編程本質論
6.4.2 echo 服務的實現
6.4.3 七步實現 finger 服務
6.5 性能評測
6.5.1 muduo 與 Boost.Asio、libevent2 的吞吐量對比
6.5.2 擊鼓傳花:對比 muduo 與 libevent2 的事件處理效率
6.5.3 muduo 與 Nginx 的吞吐量對比
6.5.4 muduo 與 ZeroMQ 的延遲對比
6.6 詳解 muduo 多線程模型
6.6.1 數獨求解服務器
6.6.2 常見的并發網絡服務程序設計方案
第 7 章 muduo 編程示例
7.1 五個簡單 TCP 示例
7.2 文件傳輸
7.3 Boost.Asio 的聊天服務器
7.3.1 TCP 分包
7.3.2 消息格式
7.3.3 編解碼器 LengthHeaderCodec
7.3.4 服務端的實現
7.3.5 客戶端的實現
7.4 muduo Buffer 類的設計與使用
7.4.1 muduo 的 IO 模型
7.4.2 為什么 non-blocking 網絡編程中應用層 buffer 是必需的
7.4.3 Buffer 的功能需求
7.4.4 Buffer 的數據結構
7.4.5 Buffer 的操作
7.4.6 其他設計方案
7.4.7 性能是不是問題
7.5 一種自動反射消息類型的 Google Protobuf 網絡傳輸方案
7.5.1 網絡編程中使用 Protobuf 的兩個先決條件
7.5.2 根據 type name 反射自動創建 Message 對象
7.5.3 Protobuf 傳輸格式
7.6 在 muduo 中實現 Protobuf 編解碼器與消息分發器
7.6.1 什么是編解碼器(codec)
7.6.2 實現 ProtobufCodec
7.6.3 消息分發器(dispatcher)有什么用
7.6.4 ProtobufCodec 與 ProtobufDispatcher 的綜合運用
7.6.5 ProtobufDispatcher 的兩種實現
7.6.6 ProtobufCodec 和 ProtobufDispatcher 有何意義
7.7 限制服務器的最大并發連接數
7.7.1 為什么要限制并發連接數
7.7.2 在 muduo 中限制并發連接數
7.8 定時器
7.8.1 程序中的時間
7.8.2 Linux 時間函數
7.8.3 muduo 的定時器接口
7.8.4 Boost.Asio Timer 示例
7.8.5 Java Netty 示例
7.9 測量兩臺機器的網絡延遲和時間差
7.10 用 timing wheel 踢掉空閑連接
7.10.1 timing wheel 原理
7.10.2 代碼實現與改進
7.11 簡單的消息廣播服務
7.12 “串并轉換”連接服務器及其自動化測試
7.13 socks4a 代理服務器
7.13.1 TCP 中繼器
7.13.2 socks4a 代理服務器
7.13.3 N : 1 與 1 : N 連接轉發
7.14 短址服務
7.15 與其他庫集成
7.15.1 UDNS
7.15.2 c-ares DNS
7.15.3 curl
7.15.4 更多
第 8 章 muduo 網絡庫設計與實現
8.0 什么都不做的 EventLoop
8.1 Reactor 的關鍵結構
8.1.1 Channel class
8.1.2 Poller class
8.1.3 EventLoop 的改動
8.2 TimerQueue 定時器
8.2.1 TimerQueue class
8.2.2 EventLoop 的改動
8.3 EventLoop::runInLoop() 函數
8.3.1 提高 TimerQueue 的線程安全性
8.3.2 EventLoopThread class
8.4 實現 TCP 網絡庫
8.5 TcpServer 接受新連接
8.5.1 TcpServer class
8.5.2 TcpConnection class
8.6 TcpConnection 斷開連接
8.7 Buffer 讀取數據
8.7.1 TcpConnection 使用 Buffer 作為輸入緩沖
8.7.2 Buffer::readFd()
8.8 TcpConnection 發送數據
8.9 完善 TcpConnection
8.9.1 SIGPIPE
8.9.2 TCP No Delay 和 TCP keepalive
8.9.3 WriteCompleteCallback 和 HighWaterMarkCallback
8.10 多線程 TcpServer
8.11 Connector
8.12 TcpClient
8.13 epoll
8.14 測試程序一覽
第 3 部分 工程實踐經驗談
第 9 章 分布式系統工程實踐
9.1 我們在技術浪潮中的位置
9.1.1 分布式系統的本質困難
9.1.2 分布式系統是個險惡的問題
9.2 分布式系統的可靠性淺說
9.2.1 分布式系統的軟件不要求 7 × 24 可靠
9.2.2 “能隨時重啟進程”作為程序設計目標
9.3 分布式系統中心跳協議的設計
9.4 分布式系統中的進程標識
9.4.1 錯誤做法
9.4.2 正確做法
9.4.3 TCP 協議的啟示
9.5 構建易于維護的分布式程序
9.6 為系統演化做準備
9.6.1 可擴展的消息格式
9.6.2 反面教材:ICE 的消息打包格式
9.7 分布式程序的自動化回歸測試
9.7.1 單元測試的能與不能
9.7.2 分布式系統測試的要點
9.7.3 分布式系統的抽象觀點
9.7.4 一種自動化的回歸測試方案
9.7.5 其他用處
9.8 分布式系統部署、監控與進程管理的幾重境界
9.8.1 境界 1:全手工操作
9.8.2 境界 2:使用零散的自動化腳本和第三方組件
9.8.3 境界 3:自制機群管理系統,集中化配置
9.8.4 境界 4:機群管理與 naming service 結合
第 10 章 C++ 編譯鏈接模型精要
10.1 C 語言的編譯模型及其成因
10.1.1 為什么 C 語言需要預處理
10.1.2 C 語言的編譯模型
10.2 C++ 的編譯模型
10.2.1 單遍編譯
10.2.2 前向聲明
10.3 C++ 鏈接(linking)
10.3.1 函數重載
10.3.2 inline 函數
10.3.3 模板
10.3.4 虛函數
10.4 工程項目中頭文件的使用規則
10.4.1 頭文件的害處
10.4.2 頭文件的使用規則
10.5 工程項目中庫文件的組織原則
10.5.1 動態庫是有害的
10.5.2 靜態庫也好不到哪兒去
10.5.3 源碼編譯是王道
第 11 章 反思 C++ 面向對象與虛函數
11.1 樸實的 C++ 設計
11.2 程序庫的二進制兼容性
11.2.1 什么是二進制兼容性
11.2.2 有哪些情況會破壞庫的 ABI
11.2.3 哪些做法多半是安全的
11.2.4 反面教材:COM
11.2.5 解決辦法
11.3 避免使用虛函數作為庫的接口
11.3.1 C++ 程序庫的作者的生存環境
11.3.2 虛函數作為庫的接口的兩大用途
11.3.3 虛函數作為接口的弊端
11.3.4 假如 Linux 系統調用以 COM 接口方式實現
11.3.5 Java 是如何應對的
11.4 動態庫接口的推薦做法
11.5 以 boost::function 和 boost::bind 取代虛函數
11.5.1 基本用途
11.5.2 對程序庫的影響
11.5.3 對面向對象程序設計的影響
11.6 iostream 的用途與局限
11.6.1 stdio 格式化輸入輸出的缺點
11.6.2 iostream 的設計初衷
11.6.3 iostream 與標準庫其他組件的交互
11.6.4 iostream 在使用方面的缺點
11.6.5 iostream 在設計方面的缺點
11.6.6 一個 300 行的 memory buffer output stream
11.6.7 現實的 C++ 程序如何做文件 IO
11.7 值語義與數據抽象
11.7.1 什么是值語義
11.7.2 值語義與生命期
11.7.3 值語義與標準庫
11.7.4 值語義與 C++ 語言
11.7.5 什么是數據抽象
11.7.6 數據抽象所需的語言設施
11.7.7 數據抽象的例子
第 12 章 C++ 經驗談
12.1 用異或來交換變量是錯誤的
12.1.1 編譯器會分別生成什么代碼
12.1.2 為什么短的代碼不一定快
12.2 不要重載全局 ::operator new()
12.2.1 內存管理的基本要求
12.2.2 重載 ::operator new() 的理由
12.2.3 ::operator new() 的兩種重載方式
12.2.4 現實的開發環境
12.2.5 重載 ::operator new() 的困境
12.2.6 解決辦法:替換 malloc()
12.2.7 為單獨的 class 重載 ::operator new() 有問題嗎
12.2.8 有必要自行定制內存分配器嗎
12.3 帶符號整數的除法與余數
12.3.1 語言標準怎么說
12.3.2 C/C++ 編譯器的表現
12.3.3 其他語言的規定
12.3.4 腳本語言解釋器代碼
12.3.5 硬件實現
12.4 在單元測試中 mock 系統調用
12.4.1 系統函數的依賴注入
12.4.2 鏈接期墊片(link seam)
12.5 慎用匿名 namespace
12.5.1 C 語言的 static 關鍵字的兩種用法
12.5.2 C++ 語言的 static 關鍵字的四種用法
12.5.3 匿名 namespace 的不利之處
12.5.4 替代辦法
12.6 采用有利于版本管理的代碼格式
12.6.1 對 diff 友好的代碼格式
12.6.2 對 grep 友好的代碼風格
12.6.3 一切為了效率
12.7 再探 std::string
12.7.1 直接拷貝(eager copy)
12.7.2 寫時復制(copy-on-write)
12.7.3 短字符串優化(SSO)
12.8 用 STL algorithm 輕松解決幾道算法面試題
12.8.1 用 next_permutation() 生成排列與組合
12.8.2 用 unique() 去除連續重復空白
12.8.3 用 {make,push,pop}_heap() 實現多路歸并
12.8.4 用 partition() 實現“重排數組,讓奇數位于偶數前面”
12.8.5 用 lower_bound() 查找 IP 地址所屬的城市
第 4 部分 附錄
附錄 A 談一談網絡編程學習經驗
附錄 B 從《C++ Primer(第 4 版)》入手學習 C++
附錄 C 關于 Boost 的看法
附錄 D 關于 TCP 并發連接的幾個思考題與試驗
參考文獻
本書主要講述采用現代 C++ 在 x86-64 Linux 上編寫多線程 TCP 網絡服務程序的主流常規技術,重點講解一種適應性較強的多線程服務器的編程模型,即 one loop per thread。這是在 Linux 下以 native 語言編寫用戶態高性能網絡程序最成熟的模式,掌握之后可順利地開發各類常見的服務端網絡應用程序。本書以 muduo 網絡庫為例,講解這種編程模型的使用方法及注意事項。本書的宗旨是貴精不貴多。掌握兩種基本的同步原語就可以滿足各種多線程同步的功能需求,還能寫出更易用的同步設施。掌握一種進程間通信方式和一種多線程網絡編程模型就足以應對日常開發任務,編寫運行于公司內網環境的分布式服務系統。
本書主要講述采用現代C++ 在x86-64 Linux 上編寫多線程TCP 網絡服務程序的主流常規技術,這也是我對過去5 年編寫生產環境下的多線程服務端程序的經驗總結。本書重點講解多線程網絡服務器的一種IO 模型,即one loop per thread。這是一種適應性較強的模型,也是Linux 下以native 語言編寫用戶態高性能網絡程序最成熟的模式,掌握之后可順利地開發各類常見的服務端網絡應用程序。本書以muduo網絡庫為例,講解這種編程模型的使用方法及注意事項。
muduo 是一個基于非阻塞IO 和事件驅動的現代C++ 網絡庫,原生支持one loop per thread 這種IO 模型。muduo 適合開發Linux 下的面向業務的多線程服務端網絡應用程序,其中“面向業務的網絡編程”的定義見附錄A。“現代C++”指的不是C++11 新標準,而是2005 年TR1 發布之后的C++ 語言和庫。與傳統C++ 相比,現代C++ 的變化主要有兩方面:資源管理(見第1 章)與事件回調(見第449 頁)。
本書不是多線程編程教程,也不是網絡編程教程,更不是C++ 教程。讀者應該已經大致讀過《UNIX 環境高級編程》、《UNIX 網絡編程》、《C++ Primer》或與之內容相近的書籍。本書不談C++11,因為目前(2012 年)主流的Linux 服務端發行版的g++ 版本都還停留在4.4,C++11 進入實用尚需一段時日。
本書適用的硬件環境是主流x86-64 服務器,多路多核CPU、幾十GB 內存、千兆以太網互聯。除了第5 章講診斷日志之外,本書不涉及文件IO。
本書分為四大部分,第1 部分“C++ 多線程系統編程”考察多線程下的對象生命期管理、線程同步方法、多線程與C++ 的結合、高效的多線程日志等。第2 部分“muduo 網絡庫”介紹使用現成的非阻塞網絡庫編寫網絡應用程序的方法,以及muduo 的設計與實現。第3 部分“工程實踐經驗談”介紹分布式系統的工程化開發方法和C++ 在工程實踐中的功能特性取舍。第4 部分“附錄”分享網絡編程和C++語言的學習經驗。
本書的宗旨是貴精不貴多。掌握兩種基本的同步原語就可以滿足各種多線程同步的功能需求,還能寫出更易用的同步設施。掌握一種進程間通信方式和一種多線程網絡編程模型就足以應對日常開發任務,編寫運行于公司內網環境的分布式服務系統。(本書不涉及分布式存儲系統,也不涉及UDP。)

術語與排版范例
本書大量使用英文術語,甚至有少量英文引文。設計模式的名字一律用英文,例如Observer、Reactor、Singleton。在中文術語不夠突出時,也會使用英文,例如class、heap、event loop、STL algorithm 等。注意幾個中文C++ 術語: 對象實體(instance)、函數重載決議(resolution)、模板具現化(instantiation)、覆寫(override)虛函數、提領(dereference)指針。本書中的英語可數名詞一般不用復數形式,例如兩個class,6 個syscall;但有時會用(s) 強調中文名詞是復數。fd 是文件描述符(file descriptor)的縮寫。“CPU 數目”一般指的是核(core)的數目。容量單位kB、MB、GB 表示的字節數分別為103、106、109,在特別強調準確數值時,會分別用KiB、MiB、GiB 表示210、220、230 字節。用諸如§11.5 表示本書第11.5 節,L42 表示上下文中出現的第42 行代碼。[JCP]、[CC2e] 等是參考文獻,見書末清單。
一般術語用普通羅馬字體,如mutex、socket;C++ 關鍵字用無襯線字體,如class、this、mutable;函數名和class 名用等寬字體,如fork(2)、muduo::EventLoop,其中fork(2) 表示系統函數fork() 的文檔位于manpage 第2 節,可以通過man 2 fork命令查看。如果函數名或類名過長,可能會折行,行末有連字號“-”,如EventLoop-ThreadPool。文件路徑和URL 采用窄字體,例如muduo/base/Date.h、http://chenshuo.com。用中文楷體表示引述別人的話。

代碼
本書的示例代碼以開源項目的形式發布在GitHub 上,地址是http://github.com/chenshuo/recipes/ 和http://github.com/chenshuo/muduo/。本書配套頁面提供全部源代碼打包下載,正文中出現的類似recipes/thread 的路徑是壓縮包內的相對路徑,讀者不難找到其對應的GitHub URL。本書引用代碼的形式如下,左側數字是文件的行號,右側的“muduo/base/Types.h”是文件路徑1。例如下面這幾行代碼是muduo::string 的typedef。

muduo/base/Types.h
15 namespace muduo
16 {
17
18 #ifdef MUDUO_STD_STRING
19 using std::string;
20 #else // !MUDUO_STD_STRING
21 typedef __gnu_cxx::__sso_string string;
22 #endif

本書假定讀者熟悉diff -u 命令的輸出格式,用于表示代碼的改動。
本書正文中出現的代碼有時為了照顧排版而略有改寫,例如改變縮進規則,去掉單行條件語句前后的花括號等。就編程風格而論,應以電子版代碼為準。
陳碩
中國香港
pagetop