青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

陳碩的Blog

發布一個基于 Reactor 模式的 C++ 網絡庫

發布一個基于 Reactor 模式的 C++ 網絡庫

陳碩 (giantchen_AT_gmail)

Blog.csdn.net/Solstice

2010 Aug 30

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

目錄

由來 1

下載與編譯 2

例子 2

基本結構 3

公開接口 4

內部實現 4

線程模型 5

結語 5

由來

半年前我寫了一篇《學之者生,用之者死——ACE歷史與簡評》,其中提到“我心目中理想的網絡庫”的樣子:

  • 線程安全,支持多核多線程
  • 不考慮可移植性,不跨平臺,只支持 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

在想清楚這些目標之后,我開始第三次嘗試編寫自己的 C++ 網絡庫。與前兩次不同,這次我一開始就想好了庫的名字,叫 muduo (木鐸),并在 Google code 上創建了項目: http://code.google.com/p/muduo/ 。muduo 的主體內容在 5 月底已經基本完成,現在我把它開源。

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

下載與編譯

下載地址: http://muduo.googlecode.com/files/muduo-0.1.0-alpha.tar.gz

SHA1 Checksum: 5d3642e311177ded89ed0d15c10921738f8c984c

Muduo 使用了 Linux 較新的系統調用,要求 Linux 的內核版本大于 2.6.28 (我自己用的是 2.6.32 )。在 Debian Squeeze / Ubuntu 10.04 LTS 上編譯測試通過,32 位和 64 位系統都能使用。

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

|-- base # 與網絡無關的基礎代碼,已提前發布

`-- net # 網絡庫

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

    |-- inspect # 基于以上 web 服務器的“窺探器”,用于報告進程的狀態

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

Muduo 是基于 Reactor 模式的網絡庫,其核心是個事件循環 EventLoop,用于響應計時器和 IO 事件。Muduo 采用基于對象(object based)而非面向對象(object oriented)的設計風格,其接口多以 boost::function + boost::bind 表達

Muduo 的頭文件明確分為客戶可見和客戶不可見兩類。客戶可見的為白底,客戶不可見的為灰底。

inc

這里簡單介紹各個頭文件及 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 的成員,生命期由后者控制。

線程模型

Muduo 的線程模型符合我主張的 one loop per thread + thread pool 模型。每個線程最多有一個 EventLoop。每個 TcpConnection 必須歸某個 EventLoop 管理,所有的 IO 會轉移到這個線程,換句話說一個 file descriptor 只能由一個線程讀寫。TcpConnection 所在的線程由其所屬的 EventLoop 決定,這樣我們可以很方便地把不同的 TCP 連接放到不同的線程去,也可以把一些 TCP 連接放到一個線程里。TcpConnection 和 EventLoop 是線程安全的,可以跨線程調用。TcpServer 直接支持多線程,它有兩種模式:

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

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

結語

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

posted on 2010-08-29 23:42 陳碩 閱讀(12107) 評論(20)  編輯 收藏 引用 所屬分類: muduo

評論

# re: 發布一個基于 Reactor 模式的 C++ 網絡庫 2010-08-30 08:25 路青飛

超贊!
有個小問題,為什么不支持Windows呢?  回復  更多評論   

# re: 發布一個基于 Reactor 模式的 C++ 網絡庫 2010-08-30 08:56 陳碩

@路青飛
因為我對 Windows 編程不熟。  回復  更多評論   

# re: 發布一個基于 Reactor 模式的 C++ 網絡庫 2010-08-30 09:07 expter

很好,下載學習下。。  回復  更多評論   

# re: 發布一個基于 Reactor 模式的 C++ 網絡庫 2010-08-30 09:48 dennis-zhuang

不支持udp是基于什么考慮?
timerQueue替換成優先隊列也是O(lg(n))的復雜度吧,而不是O(1)
貌似沒有實現基于select的Poller。
代碼很清晰,感謝。  回復  更多評論   

# re: 發布一個基于 Reactor 模式的 C++ 網絡庫 2010-08-30 10:41 陳碩

@dennis-zhuang
> 不支持udp是基于什么考慮?
因為我沒搞過 UDP 編程,沒有一手的經驗。

> timerQueue替換成優先隊列也是O(lg(n))的復雜度吧,而不是O(1)
刪除的復雜度是 O(ln n)。插入的平均復雜度是 O(1),最壞復雜度是 O(ln n)。已訂正原文,多謝。

> 貌似沒有實現基于select的Poller。
確實,因為 select 比 poll 限制更多,有了 poll 和 epoll,沒必要再實現 select。

> 代碼很清晰,感謝。
thanks.  回復  更多評論   

# re: 發布一個基于 Reactor 模式的 C++ 網絡庫 2010-09-02 12:18 梨樹陽光

非常不錯,下來看看  回復  更多評論   

# re: 發布一個基于 Reactor 模式的 C++ 網絡庫 2010-09-02 23:41 chaogu

不知樓主試過沒,Linux開50個線程機器會很卡,windows開50個的時候對機器的運行不影響。老實說我不是很明白。能不能解釋一下。
Linux是用的pthread
Windows用的是win32API
會不會是我使用不對啊(不要說開50個線程不對,我只是覺得Linux的線程應該比Windows好,開相同多的線程應該Linux好很多)。
老實說Linux我還是菜鳥。  回復  更多評論   

# re: 發布一個基于 Reactor 模式的 C++ 網絡庫 2010-09-03 08:12 陳碩

@chaogu
我沒有遇到過,你的線程函數長什么樣?用哪種同步機制?  回復  更多評論   

# re: 發布一個基于 Reactor 模式的 C++ 網絡庫[未登錄] 2010-09-03 09:10 cppexplore

@chaogu
linux的線程調度比windows的差, 有資料表明,windows上線程的調度切換是linux上的1/30大概.
另linux可以把進程和cpu綁定,而線程:低內核的linux則沒有相關函數, 2.6小版本內核有相關函數,但綁定不成功, 只有最新的linux內核才可以。
  回復  更多評論   

# re: 發布一個基于 Reactor 模式的 C++ 網絡庫 2010-09-03 11:02 chaogu

@陳碩
函數是_beginthreadex
同步用的是WaitForSingleObject。  回復  更多評論   

# re: 發布一個基于 Reactor 模式的 C++ 網絡庫 2010-09-03 11:22 陳碩

@chaogu
Linux 下呢?有沒有 busy waiting?  回復  更多評論   

# re: 發布一個基于 Reactor 模式的 C++ 網絡庫 2010-09-03 11:26 chaogu

@陳碩
其他的是一樣的。代碼上的區別只是線程上的不同。
Linux上用的就是pthread,同步用的是pthread_mutex_unlock(就是加鎖)。
Windows用WaitForSingleObject也就為了加鎖。  回復  更多評論   

# re: 發布一個基于 Reactor 模式的 C++ 網絡庫 2010-09-03 12:18 陳碩

@chaogu
Linux 上用什么方式等待?  回復  更多評論   

# re: 發布一個基于 Reactor 模式的 C++ 網絡庫 2010-09-03 13:10 chaogu

@陳碩
while(true)
難道有問題?  回復  更多評論   

# re: 發布一個基于 Reactor 模式的 C++ 網絡庫 2010-09-03 13:29 陳碩

@chaogu
循環體內有沒有 pthread_cond_wait ? 或者貼一下代碼骨架吧。  回復  更多評論   

# re: 發布一個基于 Reactor 模式的 C++ 網絡庫 2010-09-03 16:46 chaogu

1 queue<sometype> shareQueue 2 3 main{ 4 run_server() 5 } 6 run_server{ 7 //do something init 8 .... 9 10 //create thread 11 for(int i = 0;i < pollsize;++i){ 12 pthread_attr_init(attr[i]) 13 pthread_attr_setstacksize(attr[i],1024*120) 14 threads[i] = pthread_create(threadids[i],attr[i],somefunc,args[i]) 15 } 16 17 while(true){ 18 __createShareObject__(shareObject) //Pseudo-code 19 pthread_mutex_lock(&mutex); 20 shareQuueue.push(shareObject); 21 pthread_mutex_unlock(&mutex); 22 } 23 24 //clean up 25 ..... 26 } 27 28 somefunc(){ 29 while(true){ 30 pthread_mutex_lock(&mutex); 31 if(shareQueue.size() < 1){ 32 pthead_mutex_unlock(&mutex); 33 continue; 34 }else{ 35 shareObject = shareQueue.pop(); 36 pthread_mutex_unlock(&mutex); 37 } 38 __useShareObjectDoSomething__ //pseudo-code 39 } 40 } 41 42 43 不知這樣是否能看懂,不是我的代碼要保密,而是代碼有點難看
就是我看也要整半天才能看懂。這個結構也就夠清晰了。Windows里
面的結構是一樣的,只不過pthread的函數換成win32api
  回復  更多評論   

# re: 發布一個基于 Reactor 模式的 C++ 網絡庫 2010-09-03 22:32 陳碩

@chaogu
這是典型的 busy-waiting,建議改為:

19 pthread_mutex_lock(&mutex);
20 shareQuueue.push(shareObject);
++ pthread_cond_signal(&condvar);
21 pthread_mutex_unlock(&mutex);

30 pthread_mutex_lock(&mutex);
31 while (shareQueue.size() < 1){
++ pthread_cond_wait(&condvar, &mutex);
34 }
35 shareObject = shareQueue.pop();
36 pthread_mutex_unlock(&mutex);

參考:
http://github.com/chenshuo/recipes/blob/master/thread/BlockingQueue.h  回復  更多評論   

# re: 發布一個基于 Reactor 模式的 C++ 網絡庫 2010-09-04 21:19 cpp

std::vector<char> buffer_;
看過mangos里也是采用這個來裝buffer。
vector和char [固定長度],請問你認為有什么優勢呢?  回復  更多評論   

# re: 發布一個基于 Reactor 模式的 C++ 網絡庫 2010-09-04 21:27 陳碩

@cpp
vector 能伸縮唄,適合不定長的消息。  回復  更多評論   

# re: 發布一個基于 Reactor 模式的 C++ 網絡庫 2015-11-06 22:39 孫國棟

Makefile:126: recipe for target 'all' failed
什么原因,謝謝?  回復  更多評論   

<2011年8月>
31123456
78910111213
14151617181920
21222324252627
28293031123
45678910

導航

統計

常用鏈接

隨筆分類

隨筆檔案

相冊

搜索

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲国产小视频| 久久美女艺术照精彩视频福利播放| 99视频在线观看一区三区| 亚洲精品免费一二三区| 欧美一区二区免费视频| 亚洲伦伦在线| 久久精品国产欧美激情| 欧美日韩一区二区在线播放| 国产在线观看精品一区二区三区 | 久久中文字幕一区二区三区| 亚洲一区制服诱惑| 欧美日韩精品久久久| 中文在线资源观看网站视频免费不卡 | 亚洲综合色视频| 亚洲精选在线| 国产精品亚洲网站| 午夜久久电影网| 一区二区三区日韩精品| 欧美视频官网| 免费观看成人网| 一区二区三区四区在线| 欧美日韩一区二区免费在线观看| 亚洲国产精品一区二区第一页| 亚洲欧洲久久| 99这里只有精品| 香蕉久久一区二区不卡无毒影院 | 欧美日本中文字幕| 亚洲小说春色综合另类电影| 亚洲电影免费观看高清| 欧美极品aⅴ影院| 亚洲天堂久久| 久久免费黄色| 欧美一区二区在线观看| 久久免费少妇高潮久久精品99| 夜夜嗨网站十八久久| 亚洲夜晚福利在线观看| 国产精品尤物福利片在线观看| 亚洲免费大片| 国产一区二区三区自拍| 亚洲激情午夜| 一区二区免费在线播放| 亚洲综合国产| 久久一区视频| 国产区亚洲区欧美区| 亚洲一区二区动漫| 亚洲精品视频一区二区三区| 久色婷婷小香蕉久久| 日韩视频在线你懂得| 麻豆精品精华液| 两个人的视频www国产精品| 国产精品自在线| 欧美资源在线| 一本到高清视频免费精品| 亚洲在线免费视频| 国产日韩精品久久| 免费高清在线视频一区·| 亚洲春色另类小说| 亚洲欧洲精品一区二区三区不卡| 免费日韩av片| 极品日韩久久| 久久精品中文| 亚洲国产日韩精品| 中文久久乱码一区二区| 亚洲第一精品影视| 欧美激情 亚洲a∨综合| 亚洲一区二区三区涩| 蜜月aⅴ免费一区二区三区| 一区二区三区成人| 国产女主播视频一区二区| 久久精品一本久久99精品| 欧美高清视频| 免费黄网站欧美| 亚洲性夜色噜噜噜7777| 免费观看一级特黄欧美大片| 久久久夜精品| 一区二区国产精品| 国产免费亚洲高清| 麻豆精品网站| 亚洲伊人色欲综合网| 亚洲精品影院| 欧美成人综合| 久久久久高清| 欧美综合国产| 亚洲欧美日本视频在线观看| 亚洲欧美在线一区| 99精品久久免费看蜜臀剧情介绍| 国内成+人亚洲| 狠狠色狠狠色综合系列| 激情久久综艺| 一本色道久久综合亚洲精品不 | 久久精品免费电影| 亚洲午夜羞羞片| 午夜精品久久久久久久白皮肤 | 欧美成人午夜激情视频| 午夜综合激情| 亚洲综合清纯丝袜自拍| 免费久久99精品国产| 毛片一区二区三区| 久久伊伊香蕉| 免费在线亚洲欧美| 亚洲精品国精品久久99热| 亚洲欧美国产77777| 欧美不卡激情三级在线观看| 欧美性大战久久久久久久| 欧美日韩国产电影| 国产欧美日韩免费看aⅴ视频| 欧美少妇一区| 亚洲电影在线播放| 亚洲在线一区二区| 亚洲精品午夜| 欧美性淫爽ww久久久久无| 国产一区二区三区在线观看免费视频| 国产无遮挡一区二区三区毛片日本| 国产自产v一区二区三区c| 亚洲国产精品www| 免费欧美电影| 亚洲午夜在线视频| 久久在线视频| 伊人久久大香线蕉综合热线| 久久黄金**| 久久久精品2019中文字幕神马| 国产欧美日本一区视频| 亚洲精选成人| 亚洲国产91| 欧美性猛交xxxx乱大交退制版| 日韩亚洲欧美精品| 亚洲国产小视频在线观看| 美女尤物久久精品| 在线观看欧美日韩国产| 亚洲区一区二| 久久精品亚洲| 亚洲精品综合久久中文字幕| 亚洲性xxxx| 国产精品毛片一区二区三区 | 在线成人亚洲| 久久国产精品久久国产精品| 噜噜噜躁狠狠躁狠狠精品视频| 国产一区二区三区日韩| 欧美日韩卡一卡二| 亚洲日本成人网| 欧美黑人在线播放| 欧美日韩第一区日日骚| 亚洲一区二区精品视频| 久久精品成人一区二区三区| 亚洲精选久久| 麻豆久久婷婷| 午夜一区二区三视频在线观看 | 美女福利精品视频| 欧美一区二区三区免费在线看| 久久久久久久波多野高潮日日| 在线视频你懂得一区| 久久久久久久尹人综合网亚洲| 久久精品国产免费观看| 国产精品高清免费在线观看| 亚洲人被黑人高潮完整版| 国外成人免费视频| 欧美高清影院| 在线亚洲观看| 国产精品天天摸av网| 欧美一区二区在线视频| 欧美国产第二页| 欧美黑人多人双交| 99热这里只有精品8| 欧美大片在线观看一区| 亚洲黄色大片| 欧美一区二区性| 国产精品久久久久免费a∨| 亚洲字幕一区二区| 久久久av水蜜桃| 亚洲精品一区二区三区99| 欧美激情欧美狂野欧美精品| 亚洲免费伊人电影在线观看av| 亚洲视频一二三| 欧美日韩一区二区视频在线观看| 日韩一级黄色av| 久久夜色精品国产亚洲aⅴ| 国产三区二区一区久久| 欧美黑人国产人伦爽爽爽| 亚洲精品小视频在线观看| 久久av一区二区| 亚洲第一搞黄网站| 黄色在线成人| 亚洲精品美女在线| 久久偷窥视频| 一区二区三区精品| 国产精品久久久久999| 久久国产加勒比精品无码| 欧美成人首页| 免费h精品视频在线播放| 夜夜爽夜夜爽精品视频| 好吊色欧美一区二区三区四区| 欧美日韩国产免费| 欧美岛国激情| 欧美日韩1080p| 国产精品99免费看| 国产精品久久久久秋霞鲁丝 | 久久婷婷人人澡人人喊人人爽| 久久精品成人一区二区三区| 一区二区三区久久网| 一区二区三区日韩欧美|