• <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>

            陳碩的Blog

            Muduo 網(wǎng)絡(luò)編程示例之零:前言

            陳碩 (giantchen_AT_gmail)

            Blog.csdn.net/Solstice

            Muduo 全系列文章列表: http://blog.csdn.net/Solstice/category/779646.aspx

            我將會(huì)寫一系列文章,介紹用 muduo 網(wǎng)絡(luò)庫完成常見的 TCP 網(wǎng)絡(luò)編程任務(wù)。目前計(jì)劃如下:

            1. UNP 中的簡單協(xié)議,包括 echo、daytime、time、discard 等。 
            2. Boost.Asio 中的示例,包括 timer2~6、chat 等。
            3. Java Netty 中的示例,包括 discard、echo、uptime 等,其中的 discard 和 echo 帶流量統(tǒng)計(jì)功能。
            4. Python twisted 中的示例,包括 finger01~07
            5. 云風(fēng)的串并轉(zhuǎn)換連接服務(wù)器 multiplexer,包括單線程和多線程兩個(gè)版本。
            6. 用于測試兩臺(tái)機(jī)器的往返延遲的 roundtrip
            7. 用于測試兩臺(tái)機(jī)器的帶寬的 pingpong
            8. 文件傳輸
            9. 一個(gè)基于 TCP 的應(yīng)用層廣播 hub
            10. socks4a 代理服務(wù)器,包括簡單的 TCP 中繼(relay)。
            11. 一個(gè) Sudoku 服務(wù)器的演變,從單線程到多線程,從阻塞到 event-based。
            12. 一個(gè)提供短址服務(wù)的 httpd 服務(wù)器

            其中前面 7 個(gè)已經(jīng)放到了 muduo 代碼的 examples 目錄中,下載地址是: http://muduo.googlecode.com/files/muduo-0.1.5-alpha.tar.gz 

            這些例子都比較簡單,邏輯不復(fù)雜,代碼也很短,適合摘取關(guān)鍵部分放到博客上。其中一些有一定的代表性與針對(duì)性,比如“如何傳輸完整的文件”估計(jì)是網(wǎng)絡(luò)編程的初學(xué)者經(jīng)常遇到的問題。請(qǐng)注意,muduo 是設(shè)計(jì)來開發(fā)內(nèi)網(wǎng)的網(wǎng)絡(luò)程序,它沒有做任何安全方面的加強(qiáng)措施,如果用在公網(wǎng)上可能會(huì)受到攻擊,在后面的例子中我會(huì)談到這一點(diǎn)。

            本系列文章適用于 Linux 2.6.x (x > 25),主要測試發(fā)行版為 Ubuntu 10.04 LTSDebian 6.0 Squeeze,64-bit x86 硬件。

            TCP 網(wǎng)絡(luò)編程本質(zhì)論

            我認(rèn)為,TCP 網(wǎng)絡(luò)編程最本質(zhì)的是處理三個(gè)半事件:

            1. 連接的建立,包括服務(wù)端接受 (accept) 新連接和客戶端成功發(fā)起 (connect) 連接。
            2. 連接的斷開,包括主動(dòng)斷開 (close 或 shutdown) 和被動(dòng)斷開 (read 返回 0)。
            3. 消息到達(dá),文件描述符可讀。這是最為重要的一個(gè)事件,對(duì)它的處理方式?jīng)Q定了網(wǎng)絡(luò)編程的風(fēng)格(阻塞還是非阻塞,如何處理分包,應(yīng)用層的緩沖如何設(shè)計(jì)等等)。
            4. 消息發(fā)送完畢,這算半個(gè)。對(duì)于低流量的服務(wù),可以不必關(guān)心這個(gè)事件;另外,這里“發(fā)送完畢”是指將數(shù)據(jù)寫入操作系統(tǒng)的緩沖區(qū),將由 TCP 協(xié)議棧負(fù)責(zé)數(shù)據(jù)的發(fā)送與重傳,不代表對(duì)方已經(jīng)收到數(shù)據(jù)。

            這其中有很多難點(diǎn),也有很多細(xì)節(jié)需要注意,比方說:

            1. 如果要主動(dòng)關(guān)閉連接,如何保證對(duì)方已經(jīng)收到全部數(shù)據(jù)?如果應(yīng)用層有緩沖(這在非阻塞網(wǎng)絡(luò)編程中是必須的,見下文),那么如何保證先發(fā)送完緩沖區(qū)中的數(shù)據(jù),然后再斷開連接。直接調(diào)用 close(2) 恐怕是不行的。
            2. 如果主動(dòng)發(fā)起連接,但是對(duì)方主動(dòng)拒絕,如何定期 (帶 back-off) 重試?
            3. 非阻塞網(wǎng)絡(luò)編程該用邊沿觸發(fā)(edge trigger)還是電平觸發(fā)(level trigger)?(這兩個(gè)中文術(shù)語有其他譯法,我選擇了一個(gè)電子工程師熟悉的說法。)如果是電平觸發(fā),那么什么時(shí)候關(guān)注 EPOLLOUT 事件?會(huì)不會(huì)造成 busy-loop?如果是邊沿觸發(fā),如何防止漏讀造成的饑餓?epoll 一定比 poll 快嗎?
            4. 在非阻塞網(wǎng)絡(luò)編程中,為什么要使用應(yīng)用層緩沖區(qū)?假如一次讀到的數(shù)據(jù)不夠一個(gè)完整的數(shù)據(jù)包,那么這些已經(jīng)讀到的數(shù)據(jù)是不是應(yīng)該先暫存在某個(gè)地方,等剩余的數(shù)據(jù)收到之后再一并處理?見 lighttpd 關(guān)于 \r\n\r\n 分包的 bug。假如數(shù)據(jù)是一個(gè)字節(jié)一個(gè)字節(jié)地到達(dá),間隔 10ms,每個(gè)字節(jié)觸發(fā)一次文件描述符可讀 (readable) 事件,程序是否還能正常工作?lighttpd 在這個(gè)問題上出過安全漏洞。
            5. 在非阻塞網(wǎng)絡(luò)編程中,如何設(shè)計(jì)并使用緩沖區(qū)?一方面我們希望減少系統(tǒng)調(diào)用,一次讀的數(shù)據(jù)越多越劃算,那么似乎應(yīng)該準(zhǔn)備一個(gè)大的緩沖區(qū)。另一方面,我們系統(tǒng)減少內(nèi)存占用。如果有 10k 個(gè)連接,每個(gè)連接一建立就分配 64k 的讀緩沖的話,將占用 640M 內(nèi)存,而大多數(shù)時(shí)候這些緩沖區(qū)的使用率很低。muduo 用 readv 結(jié)合棧上空間巧妙地解決了這個(gè)問題。
            6. 如果使用發(fā)送緩沖區(qū),萬一接收方處理緩慢,數(shù)據(jù)會(huì)不會(huì)一直堆積在發(fā)送方,造成內(nèi)存暴漲?如何做應(yīng)用層的流量控制?
            7. 如何設(shè)計(jì)并實(shí)現(xiàn)定時(shí)器?并使之與網(wǎng)絡(luò) IO 共用一個(gè)線程,以避免鎖。

            這些問題在 muduo 的代碼中可以找到答案。

            Muduo 簡介

            我編寫 Muduo 網(wǎng)絡(luò)庫的目的之一就是簡化日常的 TCP 網(wǎng)絡(luò)編程,讓程序員能把精力集中在業(yè)務(wù)邏輯的實(shí)現(xiàn)上,而不要天天和 Sockets API 較勁。借用 Brooks 的話說,我希望 Muduo 能減少網(wǎng)絡(luò)編程中的偶發(fā)復(fù)雜性 (accidental complexity)。

            Muduo 只支持 Linux 2.6.x 下的并發(fā)非阻塞 TCP 網(wǎng)絡(luò)編程,它的安裝方法見陳碩的 blog 文章。

            Muduo 的使用非常簡單,不需要從指定的類派生,也不用覆寫虛函數(shù),只需要注冊(cè)幾個(gè)回調(diào)函數(shù)去處理前面提到的三個(gè)半事件就行了。

            以經(jīng)典的 echo 回顯服務(wù)為例:

            1. 定義 EchoServer class,不需要派生自任何基類:

             

             1 #ifndef MUDUO_EXAMPLES_SIMPLE_ECHO_ECHO_H 
             2 #define MUDUO_EXAMPLES_SIMPLE_ECHO_ECHO_H
             3 
             4 #include <muduo/net/TcpServer.h>
             5 
             6 // RFC 862 
             7 class EchoServer 
             8 
             9 public
            10   EchoServer(muduo::net::EventLoop* loop, 
            11              const muduo::net::InetAddress& listenAddr);
            12 
            13   void start();
            14 
            15 private
            16   void onConnection(const muduo::net::TcpConnectionPtr& conn);
            17 
            18   void onMessage(const muduo::net::TcpConnectionPtr& conn, 
            19                  muduo::net::Buffer* buf, 
            20                  muduo::Timestamp time);
            21 
            22   muduo::net::EventLoop* loop_; 
            23   muduo::net::TcpServer server_; 
            24 };
            25 
            26 #endif  // MUDUO_EXAMPLES_SIMPLE_ECHO_ECHO_H
            27 

             

            在構(gòu)造函數(shù)里注冊(cè)回調(diào)函數(shù):

             

             1 EchoServer::EchoServer(EventLoop* loop, 
             2                        const InetAddress& listenAddr) 
             3   : loop_(loop), 
             4     server_(loop, listenAddr, "EchoServer"
             5 
             6   server_.setConnectionCallback( 
             7       boost::bind(&EchoServer::onConnection, this, _1)); 
             8   server_.setMessageCallback( 
             9       boost::bind(&EchoServer::onMessage, this, _1, _2, _3)); 
            10 }
            11 
            12 void EchoServer::start() 
            13 
            14   server_.start(); 
            15 
            16 
            17 

             

            2. 實(shí)現(xiàn) EchoServer::onConnection() 和 EchoServer::onMessage():

             

             1 void EchoServer::onConnection(const TcpConnectionPtr& conn) 
             2 
             3   LOG_INFO << "EchoServer - " << conn->peerAddress().toHostPort() << " -> " 
             4     << conn->localAddress().toHostPort() << " is " 
             5     << (conn->connected() ? "UP" : "DOWN"); 
             6 }
             7 
             8 void EchoServer::onMessage(const TcpConnectionPtr& conn, 
             9                            Buffer* buf, 
            10                            Timestamp time) 
            11 
            12   string msg(buf->retrieveAsString()); 
            13   LOG_INFO << conn->name() << " echo " << msg.size() << " bytes at " << time.toString(); 
            14   conn->send(msg); 
            15 }
            16 

             

            3. 在 main() 里用 EventLoop 讓整個(gè)程序跑起來:

             

             1 #include "echo.h"
             2 
             3 #include <muduo/base/Logging.h> 
             4 #include <muduo/net/EventLoop.h>
             5 
             6 using namespace muduo; 
             7 using namespace muduo::net;
             8 
             9 int main() 
            10 
            11   LOG_INFO << "pid = " << getpid(); 
            12   EventLoop loop; 
            13   InetAddress listenAddr(2007); 
            14   EchoServer server(&loop, listenAddr); 
            15   server.start(); 
            16   loop.loop(); 
            17 }
            18 

             

            完整的代碼見 muduo/examples/simple/echo。
            這個(gè)幾十行的小程序?qū)崿F(xiàn)了一個(gè)并發(fā)的 echo 服務(wù)程序,可以同時(shí)處理多個(gè)連接。
            對(duì)這個(gè)程序的詳細(xì)分析見下一篇博客《Muduo 網(wǎng)絡(luò)編程示例之一:五個(gè)簡單 TCP 協(xié)議》

            (待續(xù))

            posted on 2011-02-02 01:07 陳碩 閱讀(9363) 評(píng)論(0)  編輯 收藏 引用 所屬分類: muduo

            <2011年4月>
            272829303112
            3456789
            10111213141516
            17181920212223
            24252627282930
            1234567

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            隨筆分類

            隨筆檔案

            相冊(cè)

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            色婷婷久久综合中文久久一本| 精品国产乱码久久久久久郑州公司 | 精品精品国产自在久久高清| 久久亚洲精品成人无码网站| 国产精品99久久久久久猫咪| 国产午夜精品理论片久久影视 | 精品久久久久久久中文字幕| 久久精品一区二区三区不卡| 99久久人妻无码精品系列| 久久亚洲精品中文字幕| 久久亚洲中文字幕精品有坂深雪 | 久久丝袜精品中文字幕| 久久精品国产一区二区三区不卡| 热99re久久国超精品首页| 久久综合综合久久97色| 久久精品国产91久久麻豆自制| 日本久久久久久中文字幕| 亚洲国产精品久久66| 久久综合亚洲色HEZYO国产| 区亚洲欧美一级久久精品亚洲精品成人网久久久久 | 久久午夜羞羞影院免费观看| 精品久久人妻av中文字幕| 91久久精品91久久性色| 国产成人香蕉久久久久| 欧美粉嫩小泬久久久久久久 | 久久国产热这里只有精品| 热综合一本伊人久久精品| 久久久久久伊人高潮影院| avtt天堂网久久精品| 久久久久99精品成人片三人毛片| 亚洲欧洲久久久精品| 久久精品人人做人人妻人人玩| 久久精品嫩草影院| 综合久久一区二区三区 | 伊人久久无码中文字幕| 久久久久综合网久久| 久久99久久99精品免视看动漫| 久久r热这里有精品视频| 久久久久精品国产亚洲AV无码| 国产亚洲综合久久系列| 久久91精品国产91久|