天天看點

釋出一個基于 Reactor 模式的 C++ 網絡庫

釋出一個基于 Reactor 模式的 C++ 網絡庫

陳碩 (giantchen_AT_gmail)

Blog.csdn.net/Solstice

2010 Aug 30

本文主要介紹 muduo 網絡庫的使用。其設計與實作将有另文講解。

目錄

<a href="http://www.cnblogs.com/Solstice/archive/2010/08/29/muduo_net_lib.html#_Toc17667">由來 1</a>

<a href="http://www.cnblogs.com/Solstice/archive/2010/08/29/muduo_net_lib.html#_Toc20754">下載下傳與編譯 2</a>

<a href="http://www.cnblogs.com/Solstice/archive/2010/08/29/muduo_net_lib.html#_Toc2416">例子 2</a>

<a href="http://www.cnblogs.com/Solstice/archive/2010/08/29/muduo_net_lib.html#_Toc32039">基本結構 3</a>

<a href="http://www.cnblogs.com/Solstice/archive/2010/08/29/muduo_net_lib.html#_Toc29754">公開接口 4</a>

<a href="http://www.cnblogs.com/Solstice/archive/2010/08/29/muduo_net_lib.html#_Toc24136">内部實作 4</a>

<a href="http://www.cnblogs.com/Solstice/archive/2010/08/29/muduo_net_lib.html#_Toc8317">線程模型 5</a>

<a href="http://www.cnblogs.com/Solstice/archive/2010/08/29/muduo_net_lib.html#_Toc20019">結語 5</a>

線程安全,支援多核多線程

不考慮可移植性,不跨平台,隻支援 Linux,不支援 Windows。

在不增加複雜度的前提下可以支援 FreeBSD/Darwin,友善将來用 Mac 作為開發用機,但不為它做性能優化。也就是說 IO multiplexing 使用 poll 和 epoll。

主要支援 x86-64,兼顧 IA32

不支援 UDP,隻支援 TCP

不支援 IPv6,隻支援 IPv4

不考慮廣域網應用,隻考慮區域網路

隻支援一種使用模式:non-blocking IO + one event loop per thread,不考慮阻塞 IO

API 簡單易用,隻暴露具體類和标準庫裡的類,不使用 non-trivial templates,也不使用虛函數

隻滿足常用需求的 90%,不面面俱到,必要的時候以 app 來适應 lib

隻做 library,不做成 framework

争取全部代碼在 5000 行以内(不含測試)

以上條件都滿足時,可以考慮搭配 Google Protocol Buffers RPC

本文主要介紹 muduo 網絡庫的使用,其設計與實作将有另文講解。

SHA1 Checksum: 5d3642e311177ded89ed0d15c10921738f8c984c

Muduo 采用 CMake 為 build system,安裝方法:

$ sudo apt-get install cmake

Muduo 依賴 Boost,很容易安裝:

$ sudo apt-get install libboost1.40-dev # 或 libboost1.42-dev

編譯方法很簡單:

$ tar zxf muduo-0.1.0-alpha.tar.gz

$ cd muduo/

$ ./build.sh

# 編譯生成的可執行檔案和靜态庫檔案分别位于 ../build/debug/{bin,lib}

如果要編譯 release 版,可執行

$ BUILD_TYPE=release ./build.sh

# 編譯生成的可執行檔案和靜态庫檔案分别位于 ../build/release/{bin,lib}

編譯完成之後請試運作其中的例子。比如 bin/inspector_test ,然後通過浏覽器通路 http://10.0.0.10:12345/ 或 http://10.0.0.10:12345/proc/status,其中 10.0.0.10 替換為你的 Linux box 的 IP。

Muduo 附帶了幾十個小例子,位于 examples 目錄。其中包括從 Boost.Asio、JBoss Netty、Python Twisted 等處移植過來的例子。

examples

|-- simple # 簡單網絡協定的實作

|   |-- allinone  # 在一個程式裡同時實作下面 5 個協定

|   |-- chargen   # RFC 864,可測試帶寬

|   |-- daytime # RFC 867

|   |-- discard # RFC 863

|   |-- echo # RFC 862

|   |-- time # RFC 868

|   `-- timeclient # time 協定的用戶端

|-- hub # 一個簡單的 pub/sub/hub 服務,示範應用級的廣播

|-- roundtrip # 測試兩台機器的網絡延時與時間差

|-- asio # 從 Boost.Asio 移植的例子

|   |-- chat # 聊天服務

|   `-- tutorial # 一系列 timers

|-- netty # 從 JBoss Netty 移植的例子

|   |-- discard # 可用于測試帶寬,伺服器可多線程運作

|   |-- echo # 可用于測試帶寬,伺服器可多線程運作

|   `-- uptime # TCP 長連接配接

`-- twisted # 從 Python Twisted 移植的例子

    `-- finger # finger01 ~ 07

Muduo 的目錄結構如下。

muduo

`-- net # 網絡庫

    |-- http # 一個簡單的可嵌入的 web 伺服器

    |-- inspect # 基于以上 web 伺服器的“窺探器”,用于報告程序的狀态

    `-- poller # poll(2) 和 epoll(4) 兩種 IO multiplexing 後端

Muduo 的頭檔案明确分為客戶可見和客戶不可見兩類。客戶可見的為白底,客戶不可見的為灰底。

<a href="http://images.cnblogs.com/cnblogs_com/Solstice/WindowsLiveWriter/ReactorC_14C67/inc_2.png"></a>

這裡簡單介紹各個頭檔案及 class 的作用,詳細的介紹留給以後的部落格。

Buffer 仿 Netty ChannelBuffer 的 buffer class,資料的讀寫透過 buffer 進行

InetAddress 封裝 IPv4 位址 (end point),注意,muduo 目前不能解析域名,隻認 IP

EventLoop 反應器 Reactor,使用者可以注冊計時器回調

EventLoopThread 啟動一個線程,在其中運作 EventLoop::loop()

TcpConnection 整個網絡庫的核心,封裝一次 TCP 連接配接

TcpClient 用于編寫網絡用戶端,能發起連接配接,并且有重試功能

TcpServer 用于編寫網絡伺服器,接受客戶的連接配接

在這些類中,TcpConnection 的生命期依靠 shared_ptr 控制(即使用者和庫共同控制)。Buffer 的生命期由 TcpConnection 控制。其餘類的生命期由使用者控制。

HttpServer 和 Inspector,暴露出一個 http 界面,用于監控程序的狀态,類似于 Java JMX。這麼做的原因是,《程式員修煉之道》第 6 章第 34 條提到“對于更大、更複雜的伺服器代碼,提供其操作的内部試圖的一種漂亮技術是使用内建的 Web 伺服器”,Jeff Dean 也說“(每個 Google 的伺服器程序)Export HTML-based status pages for easy diagnosis”。

Channel 是 selectable IO channel,負責注冊與響應 IO 事件,它不擁有 file descriptor。它是 Acceptor、Connector、EventLoop、TimerQueue、TcpConnection 的成員,生命期由後者控制。

Socket 封裝一個 file descriptor,并在析構時關閉 fd。它是 Acceptor、TcpConnection 的成員,生命期由後者控制。EventLoop、TimerQueue 也擁有 fd,但是不封裝為 Socket。

SocketsOps 封裝各種 sockets 系統調用。

EventLoop 封裝事件循環,也是事件分派的中心。它用 eventfd(2) 來異步喚醒,這有别于傳統的用一對 pipe(2) 的辦法。它用 TimerQueue 作為計時器管理,用 Poller 作為 IO Multiplexing。

Poller 是 PollPoller 和 EPollPoller 的基類,采用“電平觸發”的語意。它是 EventLoop 的成員,生命期由後者控制。

PollPoller 和 EPollPoller 封裝 poll(2) 和 epoll(4) 兩種 IO Multiplexing 後端。Poll 的存在價值是便于調試,因為 poll(2) 調用是上下文無關的,用 strace 很容易知道庫的行為是否正确。

Connector 用于發起 TCP 連接配接,它是 TcpClient 的成員,生命期由後者控制。

Acceptor 用于接受 TCP 連接配接,它是 TcpServer 的成員,生命期由後者控制。

TimerQueue 用 timerfd 實作定時,這有别于傳統的設定 poll/epoll_wait 的等待時長的辦法。為了簡單起見,目前用連結清單來管理 Timer,如果有必要可改為優先隊列,這樣複雜度可從 O(n) 降為 O(ln n) (某些操作甚至是 O(1))。它是 EventLoop 的成員,生命期由後者控制。

EventLoopThreadPool 用于建立 IO 線程池,也就是說把 TcpConnection 分派到一組運作 EventLoop 的線程上。它是 TcpServer 的成員,生命期由後者控制。

1. 單線程,accept 與 TcpConnection 用同一個線程做 IO。

2. 多線程,accept 與 EventLoop 在同一個線程,另外建立一個 EventLoopThreadPool,新到的連接配接會按 round-robin 方式配置設定到線程池中。

Muduo 是我對常見網絡程式設計任務的總結,用它我能很容易地編寫多線程的 TCP 伺服器和用戶端。Muduo 是我業餘時間的作品,代碼估計還有很多 bug,功能也不完善(例如不支援 signal 處理),待日後慢慢改進吧。

    本文轉自 陳碩  部落格園部落格,原文連結:http://www.cnblogs.com/Solstice/archive/2010/08/29/muduo_net_lib.html,如需轉載請自行聯系原作者

繼續閱讀