• <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ì)寫(xiě)一系列文章,介紹用 muduo 網(wǎng)絡(luò)庫(kù)完成常見(jiàn)的 TCP 網(wǎng)絡(luò)編程任務(wù)。目前計(jì)劃如下:

            1. UNP 中的簡(jiǎn)單協(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. 用于測(cè)試兩臺(tái)機(jī)器的往返延遲的 roundtrip
            7. 用于測(cè)試兩臺(tái)機(jī)器的帶寬的 pingpong
            8. 文件傳輸
            9. 一個(gè)基于 TCP 的應(yīng)用層廣播 hub
            10. socks4a 代理服務(wù)器,包括簡(jiǎn)單的 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 

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

            本系列文章適用于 Linux 2.6.x (x > 25),主要測(cè)試發(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. 連接的斷開(kāi),包括主動(dòng)斷開(kāi) (close 或 shutdown) 和被動(dòng)斷開(kāi) (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ù)寫(xiě)入操作系統(tǒng)的緩沖區(qū),將由 TCP 協(xié)議棧負(fù)責(zé)數(shù)據(jù)的發(fā)送與重傳,不代表對(duì)方已經(jīng)收到數(shù)據(jù)。

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

            1. 如果要主動(dòng)關(guān)閉連接,如何保證對(duì)方已經(jīng)收到全部數(shù)據(jù)?如果應(yīng)用層有緩沖(這在非阻塞網(wǎng)絡(luò)編程中是必須的,見(jiàn)下文),那么如何保證先發(fā)送完緩沖區(qū)中的數(shù)據(jù),然后再斷開(kāi)連接。直接調(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ù)語(yǔ)有其他譯法,我選擇了一個(gè)電子工程師熟悉的說(shuō)法。)如果是電平觸發(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ù)收到之后再一并處理?見(jiàn) lighttpd 關(guān)于 \r\n\r\n 分包的 bug。假如數(shù)據(jù)是一個(gè)字節(jié)一個(gè)字節(jié)地到達(dá),間隔 10ms,每個(gè)字節(jié)觸發(fā)一次文件描述符可讀 (readable) 事件,程序是否還能正常工作?lighttpd 在這個(gè)問(wèn)題上出過(guò)安全漏洞
            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è)問(wèn)題。
            6. 如果使用發(fā)送緩沖區(qū),萬(wàn)一接收方處理緩慢,數(shù)據(jù)會(huì)不會(huì)一直堆積在發(fā)送方,造成內(nèi)存暴漲?如何做應(yīng)用層的流量控制?
            7. 如何設(shè)計(jì)并實(shí)現(xiàn)定時(shí)器?并使之與網(wǎng)絡(luò) IO 共用一個(gè)線程,以避免鎖。

            這些問(wèn)題在 muduo 的代碼中可以找到答案。

            Muduo 簡(jiǎn)介

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

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

            Muduo 的使用非常簡(jiǎn)單,不需要從指定的類派生,也不用覆寫(xiě)虛函數(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è)程序跑起來(lái):

             

             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 

             

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

            (待續(xù))

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

            <2012年7月>
            24252627282930
            1234567
            891011121314
            15161718192021
            22232425262728
            2930311234

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            隨筆分類

            隨筆檔案

            相冊(cè)

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            国产精品久久新婚兰兰| 亚洲AV日韩精品久久久久久久| 一级a性色生活片久久无| 伊人色综合九久久天天蜜桃| 久久丫精品国产亚洲av不卡| 久久久精品免费国产四虎| 亚洲国产成人精品91久久久| 99国产精品久久| 久久99热这里只有精品国产| 久久免费国产精品一区二区| 久久人人爽人人爽人人片AV不| 久久精品国产亚洲av高清漫画| 亚洲国产成人久久一区久久| 99麻豆久久久国产精品免费| 精品久久久无码人妻中文字幕 | 欧美久久综合性欧美| 区亚洲欧美一级久久精品亚洲精品成人网久久久久 | 国产精品美女久久福利网站| 欧美伊香蕉久久综合类网站| 国产偷久久久精品专区| 性做久久久久久久久| 99久久精品九九亚洲精品| 久久99热只有频精品8| 99久久精品免费看国产一区二区三区| 亚洲国产精品久久久久久| 久久精品国产亚洲AV香蕉| av色综合久久天堂av色综合在| 无码任你躁久久久久久久| 久久久精品日本一区二区三区| 色偷偷888欧美精品久久久| 久久人爽人人爽人人片AV| 亚洲αv久久久噜噜噜噜噜| 老男人久久青草av高清| 久久久久青草线蕉综合超碰| 亚洲精品无码久久不卡| 久久99这里只有精品国产| 久久天天婷婷五月俺也去| 久久久久久曰本AV免费免费| 香蕉久久夜色精品国产尤物| 国产精品中文久久久久久久| 精品国产日韩久久亚洲|