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

            談一談網(wǎng)絡(luò)編程學(xué)習(xí)經(jīng)驗(06-08更新)

            談一談網(wǎng)絡(luò)編程學(xué)習(xí)經(jīng)驗

            陳碩

            giantchen@gmail.com

            blog.csdn.net/Solstice

            2011-06-08

            PDF 版下載:https://github.com/downloads/chenshuo/documents/LearningNetworkProgramming.pdf

            本文談一談我在學(xué)習(xí)網(wǎng)絡(luò)編程方面的一些個人經(jīng)驗。“網(wǎng)絡(luò)編程”這個術(shù)語的范圍很廣,本文指用Sockets API開發(fā)基于TCP/IP的網(wǎng)絡(luò)應(yīng)用程序,具體定義見“網(wǎng)絡(luò)編程的各種任務(wù)角色”一節(jié)。

            受限于本人的經(jīng)歷和經(jīng)驗,這篇文章的適應(yīng)范圍是:

            · x86-64 Linux服務(wù)端網(wǎng)絡(luò)編程,直接或間接使用 Sockets API

            · 公司內(nèi)網(wǎng)。不一定是局域網(wǎng),但總體位于公司防火墻之內(nèi),環(huán)境可控

            本文可能不適合:

            · PC客戶端網(wǎng)絡(luò)編程,程序運行在客戶的PC上,環(huán)境多變且不可控

            · Windows網(wǎng)絡(luò)編程

            · 面向公網(wǎng)的服務(wù)程序

            · 高性能網(wǎng)絡(luò)服務(wù)器

            本文分兩個部分:

            1. 網(wǎng)絡(luò)編程的一些胡思亂想,談?wù)勎覍@一領(lǐng)域的認識

            2. 幾本必看的書,基本上還是W. Richard Stevents那幾本

            另外,本文沒有特別說明時均暗指TCP協(xié)議,“連接”是“TCP連接”,“服務(wù)端”是“TCP服務(wù)端”。

            網(wǎng)絡(luò)編程的一些胡思亂想

            以下胡亂列出我對網(wǎng)絡(luò)編程的一些想法,前后無關(guān)聯(lián)。

            網(wǎng)絡(luò)編程是什么?

            網(wǎng)絡(luò)編程是什么?是熟練使用Sockets API嗎?說實話,在實際項目里我只用過兩次Sockets API,其他時候都是使用封裝好的網(wǎng)絡(luò)庫。

            第一次是2005年在學(xué)校做一個羽毛球賽場計分系統(tǒng):我用C# 編寫運行在PC機上的軟件,負責(zé)比分的顯示;再用C# 寫了運行在PDA上的計分界面,記分員拿著PDA記錄比分;這兩部分程序通過 TCP協(xié)議相互通信。這其實是個簡單的分布式系統(tǒng),體育館有不止一片場地,每個場地都有一名拿PDA的記分員,每個場地都有兩臺顯示比分的PC機(顯示器是42吋平板電視,放在場地的對角,這樣兩邊看臺的觀眾都能看到比分)。這兩臺PC機功能不完全一樣,一臺只負責(zé)顯示當(dāng)前比分,另一臺還要負責(zé)與PDA通信,并更新數(shù)據(jù)庫里的比分信息。此外,還有一臺PC機負責(zé)周期性地從數(shù)據(jù)庫讀出全部7片場地的比分,顯示在體育館墻上的大屏幕上。這臺PC上還運行著一個程序,負責(zé)生成比分數(shù)據(jù)的靜態(tài)頁面,通過FTP上傳發(fā)布到某門戶網(wǎng)站的體育頻道。系統(tǒng)中還有一個錄入賽程(參賽隊,運動員,出場順序等)數(shù)據(jù)庫的程序,運行在數(shù)據(jù)庫服務(wù)器上。算下來整個系統(tǒng)有十來個程序,運行在二十多臺設(shè)備(PC和PDA)上,還要考慮可靠性。將來有機會把這個小系統(tǒng)仔細講一講,挺有意思的。

            這是我第一次寫實際項目中的網(wǎng)絡(luò)程序,當(dāng)時寫下來的感覺是像寫命令行與用戶交互的程序:程序在命令行輸出一句提示語,等待客戶輸入一句話,然后處理客戶輸入,再輸出下一句提示語,如此循環(huán)。只不過這里的“客戶”不是人,而是另一個程序。在建立好TCP連接之后,雙方的程序都是read/write循環(huán)(為求簡單,我用的是blocking讀寫),直到有一方斷開連接。

            第二次是2010年編寫muduo網(wǎng)絡(luò)庫,我再次拿起了Sockets API,寫了一個基于Reactor模式的C++ 網(wǎng)絡(luò)庫。寫這個庫的目的之一就是想讓日常的網(wǎng)絡(luò)編程從Sockets API的瑣碎細節(jié)中解脫出來,讓程序員專注于業(yè)務(wù)邏輯,把時間用在刀刃上。Muduo 網(wǎng)絡(luò)庫的示例代碼包含了幾十個網(wǎng)絡(luò)程序,這些示例程序都沒有直接使用Sockets API。

            在此之外,無論是實習(xí)還是工作,雖然我寫的程序都會通過TCP協(xié)議與其他程序打交道,但我沒有直接使用過Sockets API。對于TCP網(wǎng)絡(luò)編程,我認為核心是處理“三個半事件”,見《Muduo 網(wǎng)絡(luò)編程示例之零:前言》中的“TCP 網(wǎng)絡(luò)編程本質(zhì)論”。程序員的主要工作是在事件處理函數(shù)中實現(xiàn)業(yè)務(wù)邏輯,而不是和Sockets API較勁。

            這里還是沒有說清楚“網(wǎng)絡(luò)編程”是什么,請繼續(xù)閱讀后文“網(wǎng)絡(luò)編程的各種任務(wù)角色”。

            學(xué)習(xí)網(wǎng)絡(luò)編程有用嗎?

            以上說的是比較底層的網(wǎng)絡(luò)編程,程序代碼直接面對從TCP或UDP收到的數(shù)據(jù)以及構(gòu)造數(shù)據(jù)包發(fā)出去。在實際工作中,另一種常見 的情況是通過各種 client library 來與服務(wù)端打交道,或者在現(xiàn)成的框架中填空來實現(xiàn)server,或者采用更上層的通信方式。比如用libmemcached與memcached打交道,使用libpq來與PostgreSQL 打交道,編寫Servlet來響應(yīng)http請求,使用某種RPC與其他進程通信,等等。這些情況都會發(fā)生網(wǎng)絡(luò)通信,但不一定算作“網(wǎng)絡(luò)編程”。如果你的工作是前面列舉的這些,學(xué)習(xí)TCP/IP網(wǎng)絡(luò)編程還有用嗎?

            我認為還是有必要學(xué)一學(xué),至少在troubleshooting 的時候有用。無論如何,這些library或framework都會調(diào)用底層的Sockets API來實現(xiàn)網(wǎng)絡(luò)功能。當(dāng)你的程序遇到一個線上問題,如果你熟悉Sockets API,那么從strace不難發(fā)現(xiàn)程序卡在哪里,盡管可能你沒有直接調(diào)用這些Sockets API。另外,熟悉TCP/IP協(xié)議、會用tcpdump也大大有助于分析解決線上網(wǎng)絡(luò)服務(wù)問題。

            在什么平臺上學(xué)習(xí)網(wǎng)絡(luò)編程?

            對于服務(wù)端網(wǎng)絡(luò)編程,我建議在Linux上學(xué)習(xí)。

            如果在10年前,這個問題的答案或許是FreeBSD,因為FreeBSD根正苗紅,在2000年那一次互聯(lián)網(wǎng)浪潮中扮演了重要角色,是很多公司首選的免費服務(wù)器操作系統(tǒng)。2000年那會兒Linux還遠未成熟,連epoll都還沒有實現(xiàn)。(FreeBSD在2001年發(fā)布4.1版,加入了kqueue,從此C10k不是問題。)

            10年后的今天,事情起了變化,Linux成為了市場份額最大的服務(wù)器操作系統(tǒng)(http://en.wikipedia.org/wiki/Usage_share_of_operating_systems)。在Linux這種大眾系統(tǒng)上學(xué)網(wǎng)絡(luò)編程,遇到什么問題會比較容易解決。因為用的人多,你遇到的問題別人多半也遇到過;同樣因為用的人多,如果真的有什么內(nèi)核bug,很快就會得到修復(fù),至少有work around的辦法。如果用別的系統(tǒng),可能一個問題發(fā)到論壇上半個月都不會有人理。從內(nèi)核源碼的風(fēng)格看,F(xiàn)reeBSD更干凈整潔,注釋到位,但是無奈它的市場份額遠不如Linux,學(xué)習(xí)Linux是更好的技術(shù)投資。

            可移植性重要嗎?

            寫網(wǎng)絡(luò)程序要不要考慮移植性?這取決于項目需要,如果貴公司做的程序要賣給其他公司,而對方可能使用Windows、Linux、FreeBSD、Solaris、AIX、HP-UX等等操作系統(tǒng),這時候考慮移植性。如果編寫公司內(nèi)部的服務(wù)器上用的網(wǎng)絡(luò)程序,那么大可只關(guān)注一個平臺,比如Linux。因為編寫和維護可移植的網(wǎng)絡(luò)程序的代價相當(dāng)高,平臺間的差異可能遠比想象中大,即便是POSIX系統(tǒng)之間也有不小的差異(比如Linux沒有SO_NOSIGPIPE選項),錯誤的返回碼也大不一樣。

            我就不打算把muduo往Windows或其他操作系統(tǒng)移植。如果需要編寫可移植的網(wǎng)絡(luò)程序,我寧愿用libevent或者Java Netty這樣現(xiàn)成的庫,把臟活累活留給別人。

            網(wǎng)絡(luò)編程的各種任務(wù)角色

            計算機網(wǎng)絡(luò)是個 big topic,涉及很多人物和角色,既有開發(fā)人員,也有運維人員。比方說:公司內(nèi)部兩臺機器之間 ping 不通,通常由網(wǎng)絡(luò)運維人員解決,看看是布線有問題還是路由器設(shè)置不對;兩臺機器能ping通,但是程序連不上,經(jīng)檢查是本機防火墻設(shè)置有問題,通常由系統(tǒng)管理員解決;兩臺機器能連上,但是丟包很嚴重,發(fā)現(xiàn)是網(wǎng)卡或者交換機的網(wǎng)口故障,由硬件維修人員解決;兩臺機器的程序能連上,但是偶爾發(fā)過去的請求得不到響應(yīng),通常是程序bug,應(yīng)該由開發(fā)人員解決。

            本文主要關(guān)心開發(fā)人員這一角色。下面簡單列出一些我能想到的跟網(wǎng)絡(luò)打交道的編程任務(wù),其中前三項是面向網(wǎng)絡(luò)本身,后面幾項是在計算機網(wǎng)絡(luò)之上構(gòu)建信息系統(tǒng)。

            1. 開發(fā)網(wǎng)絡(luò)設(shè)備,編寫防火墻、交換機、路由器的固件 firmware

            2. 開發(fā)或移植網(wǎng)卡的驅(qū)動

            3. 移植或維護TCP/IP協(xié)議棧(特別是在嵌入式系統(tǒng)上)

            4. 開發(fā)或維護標準的網(wǎng)絡(luò)協(xié)議程序,HTTP、FTP、DNS、SMTP、POP3、NFS

            5. 開發(fā)標準網(wǎng)絡(luò)協(xié)議的“附加品”,比如HAProxy、squid、varnish等web load balancer

            6. 開發(fā)標準或非標準網(wǎng)絡(luò)服務(wù)的客戶端庫,比如ZooKeeper客戶端庫,memcached客戶端庫

            7. 開發(fā)與公司業(yè)務(wù)直接相關(guān)的網(wǎng)絡(luò)服務(wù)程序,比如即時聊天軟件的后臺服務(wù)器,網(wǎng)游服務(wù)器,金融交易系統(tǒng),互聯(lián)網(wǎng)企業(yè)用的分布式海量存儲,微博發(fā)帖的內(nèi)部廣播通知,等等

            8. 客戶端程序中涉及網(wǎng)絡(luò)的部分,比如郵件客戶端中與 POP3、SMTP通信的部分,以及網(wǎng)游的客戶端程序中與服務(wù)器通信的部分

            本文所指的“網(wǎng)絡(luò)編程”專指第7項,即在TCP/IP協(xié)議之上開發(fā)業(yè)務(wù)軟件。

            面向業(yè)務(wù)的網(wǎng)絡(luò)編程的特點

            跟開發(fā)通用的網(wǎng)絡(luò)程序不同,開發(fā)面向公司業(yè)務(wù)的專用網(wǎng)絡(luò)程序有其特點:

            · 業(yè)務(wù)邏輯比較復(fù)雜,而且時常變化

            如果寫一個HTTP服務(wù)器,在大致實現(xiàn)HTTP /1.1標準之后,程序的主體功能一般不會有太大的變化,程序員會把時間放在性能調(diào)優(yōu)和bug修復(fù)上。而開發(fā)針對公司業(yè)務(wù)的專用程序時,功能說明書(spec)很可能不如HTTP/1.1標準那么細致明確。更重要的是,程序是快速演化的。以即時聊天工具的后臺服務(wù)器為例,可能第一版只支持在線聊天;幾個月之后發(fā)布第二版,支持離線消息;又過了幾個月,第三版支持隱身聊天;隨后,第四版支持上傳頭像;如此等等。這要求程序員能快速響應(yīng)新的業(yè)務(wù)需求,公司才能保持競爭力。

            · 不一定需要遵循公認的通信協(xié)議標準

            比方說網(wǎng)游服務(wù)器就沒什么協(xié)議標準,反正客戶端和服務(wù)端都是本公司開發(fā),如果發(fā)現(xiàn)目前的協(xié)議設(shè)計有問題,兩邊一起改了就是了。

            · 程序結(jié)構(gòu)沒有定論

            對于高并發(fā)大吞吐的標準網(wǎng)絡(luò)服務(wù),一般采用單線程事件驅(qū)動的方式開發(fā),比如HAProxy、lighttpd等都是這個模式。但是對于專用的業(yè)務(wù)系統(tǒng),其業(yè)務(wù)邏輯比較復(fù)雜,占用較多的CPU資源,這種單線程事件驅(qū)動方式不見得能發(fā)揮現(xiàn)在多核處理器的優(yōu)勢。這留給程序員比較大的自由發(fā)揮空間,做好了橫掃千軍,做爛了一敗涂地。

            · 性能評判的標準不同

            如果開發(fā)httpd這樣的通用服務(wù),必然會和開源的Nginx、lighttpd等高性能服務(wù)器比較,程序員要投入相當(dāng)?shù)木θ?yōu)化程序,才能在市場上占有一席之地。而面向業(yè)務(wù)的專用網(wǎng)絡(luò)程序不一定有開源的實現(xiàn)以供對比性能,程序員通常更加注重功能的穩(wěn)定性與開發(fā)的便捷性。性能只要一代比一代強即可。

            · 網(wǎng)絡(luò)編程起到支撐作用,但不處于主導(dǎo)地位

            程序員的主要工作是實現(xiàn)業(yè)務(wù)邏輯,而不只是實現(xiàn)網(wǎng)絡(luò)通信協(xié)議。這要求程序員深入理解業(yè)務(wù)。程序的性能瓶頸不一定在網(wǎng)絡(luò)上,瓶頸有可能是CPU、Disk IO、數(shù)據(jù)庫等等,這時優(yōu)化網(wǎng)絡(luò)方面的代碼并不能提高整體性能。只有對所在的領(lǐng)域有深入的了解,明白各種因素的權(quán)衡(trade-off),才能做出一些有針對性的優(yōu)化。

            幾個術(shù)語

            互聯(lián)網(wǎng)上的很多口水戰(zhàn)是由對同一術(shù)語的不同理解引起的,比我寫的《多線程服務(wù)器的適用場合》就曾經(jīng)人被說是“掛羊頭賣狗肉”,因為這篇文章中舉的 master例子“根本就算不上是個網(wǎng)絡(luò)服務(wù)器。因為它的瓶頸根本就跟網(wǎng)絡(luò)無關(guān)。”

            · 網(wǎng)絡(luò)服務(wù)器

            “網(wǎng)絡(luò)服務(wù)器”這個術(shù)語確實含義模糊,到底指硬件還是軟件?到底是服務(wù)于網(wǎng)絡(luò)本身的機器(交換機、路由器、防火墻、NAT),還是利用網(wǎng)絡(luò)為其他人或程序提供服務(wù)的機器(打印服務(wù)器、文件服務(wù)器、郵件服務(wù)器)。每個人根據(jù)自己熟悉的領(lǐng)域,可能會有不同的解讀。比方說或許有人認為只有支持高并發(fā)高吞吐的才算是網(wǎng)絡(luò)服務(wù)器。

            為了避免無謂的爭執(zhí),我只用“網(wǎng)絡(luò)服務(wù)程序”或者“網(wǎng)絡(luò)應(yīng)用程序”這種含義明確的術(shù)語。“開發(fā)網(wǎng)絡(luò)服務(wù)程序”通常不會造成誤解。

            · 客戶端?服務(wù)端?

            在TCP網(wǎng)絡(luò)編程里邊,客戶端和服務(wù)端很容易區(qū)分,主動發(fā)起連接的是客戶端,被動接受連接的是服務(wù)端。當(dāng)然,這個“客戶端”本身也可能是個后臺服務(wù)程序,HTTP Proxy對HTTP Server來說就是個客戶端。

            · 客戶端編程?服務(wù)端編程?

            但是“服務(wù)端編程”和“客戶端編程”就不那么好區(qū)分。比如 Web crawler,它會主動發(fā)起大量連接,扮演的是HTTP客戶端的角色,但似乎應(yīng)該歸入“服務(wù)端編程”。又比如寫一個 HTTP proxy,它既會扮演服務(wù)端——被動接受 web browser 發(fā)起的連接,也會扮演客戶端——主動向 HTTP server 發(fā)起連接,它究竟算服務(wù)端還是客戶端?我猜大多數(shù)人會把它歸入服務(wù)端編程。

            那么究竟如何定義“服務(wù)端編程”?

            服務(wù)端編程需要處理大量并發(fā)連接?也許是,也許不是。比如云風(fēng)在一篇介紹網(wǎng)游服務(wù)器的博客http://blog.codingnow.com/2006/04/iocp_kqueue_epoll.html中就談到,網(wǎng)游中用到的“連接服務(wù)器”需要處理大量連接,而“邏輯服務(wù)器”只有一個外部連接。那么開發(fā)這種網(wǎng)游“邏輯服務(wù)器”算服務(wù)端編程還是客戶端編程呢?

            我認為,“服務(wù)端網(wǎng)絡(luò)編程”指的是編寫沒有用戶界面的長期運行的網(wǎng)絡(luò)程序,程序默默地運行在一臺服務(wù)器上,通過網(wǎng)絡(luò)與其他程序打交道,而不必和人打交道。與之對應(yīng)的是客戶端網(wǎng)絡(luò)程序,要么是短時間運行,比如wget;要么是有用戶界面(無論是字符界面還是圖形界面)。本文主要談服務(wù)端網(wǎng)絡(luò)編程。

            7x24重要嗎?內(nèi)存碎片可怕嗎?

            一談到服務(wù)端網(wǎng)絡(luò)編程,有人立刻會提出7x24運行的要求。對于某些網(wǎng)絡(luò)設(shè)備而言,這是合理的需求,比如交換機、路由器。對于開發(fā)商業(yè)系統(tǒng),我認為要求程序7x24運行通常是系統(tǒng)設(shè)計上考慮不周。具體見《分布式系統(tǒng)的工程化開發(fā)方法》第20頁起。重要的不是7x24,而是在程序不必做到7x24的情況下也能達到足夠高的可用性。一個考慮周到的系統(tǒng)應(yīng)該允許每個進程都能隨時重啟,這樣才能在廉價的服務(wù)器硬件上做到高可用性。

            既然不要求7x24,那么也不必害怕內(nèi)存碎片,理由如下:

            · 64-bit系統(tǒng)的地址空間足夠大,不會出現(xiàn)沒有足夠的連續(xù)空間這種情況。

            · 現(xiàn)在的內(nèi)存分配器(malloc及其第三方實現(xiàn))今非昔比,除了memcached這種純以內(nèi)存為賣點的程序需要自己設(shè)計分配器之外,其他網(wǎng)絡(luò)程序大可使用系統(tǒng)自帶的malloc或者某個第三方實現(xiàn)。

            · Linux Kernel也大量用到了動態(tài)內(nèi)存分配。既然操作系統(tǒng)內(nèi)核都不怕動態(tài)分配內(nèi)存造成碎片,應(yīng)用程序為什么要害怕?

            · 內(nèi)存碎片如何度量?有沒有什么工具能為當(dāng)前進程的內(nèi)存碎片狀況評個分?如果不能比較兩種方案的內(nèi)存碎片程度,談何優(yōu)化?

            有人為了避免內(nèi)存碎片,不使用STL容器,也不敢new/delete,這算是premature optimization還是因噎廢食呢?

            協(xié)議設(shè)計是網(wǎng)絡(luò)編程的核心

            對于專用的業(yè)務(wù)系統(tǒng),協(xié)議設(shè)計是核心任務(wù),決定了系統(tǒng)的開發(fā)難度與可靠性,但是這個領(lǐng)域還沒有形成大家公認的設(shè)計流程。

            系統(tǒng)中哪個程序發(fā)起連接,哪個程序接受連接?如果寫標準的網(wǎng)絡(luò)服務(wù),那么這不是問題,按RFC來就行了。自己設(shè)計業(yè)務(wù)系統(tǒng),有沒有章法可循?以網(wǎng)游為例,到底是連接服務(wù)器主動連接邏輯服務(wù)器,還是邏輯服務(wù)器主動連接“連接服務(wù)器”?似乎沒有定論,兩種做法都行。一般可以按照“依賴->被依賴”的關(guān)系來設(shè)計發(fā)起連接的方向。

            比新建連接難的是關(guān)閉連接。在傳統(tǒng)的網(wǎng)絡(luò)服務(wù)中(特別是短連接服務(wù)),不少是服務(wù)端主動關(guān)閉連接,比如daytime、HTTP/1.0。也有少部分是客戶端主動關(guān)閉連接,通常是些長連接服務(wù),比如 echo、chargen等。我們自己的業(yè)務(wù)系統(tǒng)該如何設(shè)計連接關(guān)閉協(xié)議呢?

            服務(wù)端主動關(guān)閉連接的缺點之一是會多占用服務(wù)器資源。服務(wù)端主動關(guān)閉連接之后會進入TIME_WAIT狀態(tài),在一段時間之內(nèi)hold住一些內(nèi)核資源。如果并發(fā)訪問量很高,這會影響服務(wù)端的處理能力。這似乎暗示我們應(yīng)該把協(xié)議設(shè)計為客戶端主動關(guān)閉,讓TIME_WAIT狀態(tài)分散到多臺客戶機器上,化整為零。

            這又有另外的問題:客戶端賴著不走怎么辦?會不會造成拒絕服務(wù)攻擊?或許有一個二者結(jié)合的方案:客戶端在收到響應(yīng)之后就應(yīng)該主動關(guān)閉,這樣把 TIME_WAIT 留在客戶端。服務(wù)端有一個定時器,如果客戶端若干秒鐘之內(nèi)沒有主動斷開,就踢掉它。這樣善意的客戶端會把TIME_WAIT留給自己,buggy的客戶端會把 TIME_WAIT留給服務(wù)端。或者干脆使用長連接協(xié)議,這樣避免頻繁創(chuàng)建銷毀連接。

            比連接的建立與斷開更重要的是設(shè)計消息協(xié)議。消息格式很好辦,XML、JSON、Protobuf都是很好的選擇;難的是消息內(nèi)容。一個消息應(yīng)該包含哪些內(nèi)容?多個程序相互通信如何避免race condition(見《分布式系統(tǒng)的工程化開發(fā)方法》p.16的例子)?系統(tǒng)的全局狀態(tài)該如何躍遷?可惜這方面可供參考的例子不多,也沒有太多通用的指導(dǎo)原則,我知道的只有30年前提出的end-to-end principle和happens-before relationship。只能從實踐中慢慢積累了。

            網(wǎng)絡(luò)編程的三個層次

            侯捷先生在《漫談程序員與編程》中講到 STL 運用的三個檔次:“會用STL,是一種檔次。對STL原理有所了解,又是一個檔次。追蹤過STL源碼,又是一個檔次。第三種檔次的人用起 STL 來,虎虎生風(fēng)之勢絕非第一檔次的人能夠望其項背。”

            我認為網(wǎng)絡(luò)編程也可以分為三個層次:

            1. 讀過教程和文檔

            2. 熟悉本系統(tǒng)TCP/IP協(xié)議棧的脾氣

            3. 自己寫過一個簡單的TCP/IP stack

            第一個層次是基本要求,讀過《Unix網(wǎng)絡(luò)編程》這樣的編程教材,讀過《TCP/IP詳解》基本理解TCP/IP協(xié)議,讀過本系統(tǒng)的manpage。這個層次可以編寫一些基本的網(wǎng)絡(luò)程序,完成常見的任務(wù)。但網(wǎng)絡(luò)編程不是照貓畫虎這么簡單,若是按照manpage的功能描述就能編寫產(chǎn)品級的網(wǎng)絡(luò)程序,那人生就太幸福了。

            第二個層次,熟悉本系統(tǒng)的TCP/IP協(xié)議棧參數(shù)設(shè)置與優(yōu)化是開發(fā)高性能網(wǎng)絡(luò)程序的必備條件。摸透協(xié)議棧的脾氣還能解決工作中遇到的比較復(fù)雜的網(wǎng)絡(luò)問題。拿Linux的TCP/IP協(xié)議棧來說:

            · 有可能出現(xiàn)自連接(見《學(xué)之者生,用之者死——ACE歷史與簡評》舉的三個硬傷),程序應(yīng)該有所準備。

            · Linux的內(nèi)核會有bug,比如某種TCP擁塞控制算法曾經(jīng)出現(xiàn)TCP window clamping(窗口箝位)bug,導(dǎo)致吞吐量暴跌,可以選用其他擁塞控制算法來繞開(work around)這個問題。

            這些陰暗角落在manpage里沒有描述,要通過其他渠道了解。

            編寫可靠的網(wǎng)絡(luò)程序的關(guān)鍵是熟悉各種場景下的error code(文件描述符用完了如何?本地ephemeral port暫時用完,不能發(fā)起新連接怎么辦?服務(wù)端新建并發(fā)連接太快,backlog用完了,客戶端connect會返回什么錯誤?),有的在manpage里有描述,有的要通過實踐或閱讀源碼獲得。

            第三個層次,通過自己寫一個簡單的TCP/IP協(xié)議棧,能大大加深對TCP/IP的理解,更能明白TCP為什么要這么設(shè)計,有哪些因素制約,每一步操作的代價是什么,寫起網(wǎng)絡(luò)程序來更是成竹在胸。

            其實實現(xiàn)TCP/IP只需要操作系統(tǒng)提供三個接口函數(shù):一個函數(shù),兩個回調(diào)函數(shù)。分別是:send_packet()、on_receive_packet()、on_timer()。多年前有一篇文章《使用libnet與libpcap構(gòu)造TCP/IP協(xié)議軟件》介紹了在用戶態(tài)實現(xiàn)TCP/IP的方法。lwIP也是很好的借鑒對象。

            如果有時間,我打算自己寫一個Mini/Tiny/Toy/Trivial/Yet-Another TCP/IP。我準備換一個思路,用TUN/TAP設(shè)備在用戶態(tài)實現(xiàn)一個能與本機點對點通信的TCP/IP協(xié)議棧,這樣那三個接口函數(shù)就表現(xiàn)為我最熟悉的文件讀寫。在用戶態(tài)實現(xiàn)的好處是便于調(diào)試,協(xié)議棧做成靜態(tài)庫,與應(yīng)用程序鏈接到一起(庫的接口不必是標準的Sockets API)。做完這一版,還可以繼續(xù)發(fā)揮,用FTDI的USB-SPI接口芯片連接ENC28J60適配器,做一個真正獨立于操作系統(tǒng)的TCP/IP stack。如果只實現(xiàn)最基本的IP、ICMP Echo、TCP的話,代碼應(yīng)能控制在3000行以內(nèi);也可以實現(xiàn)UDP,如果應(yīng)用程序需要用到DNS的話。

            最主要的三個例子

            我認為TCP網(wǎng)絡(luò)編程有三個例子最值得學(xué)習(xí)研究,分別是echo、chat、proxy,都是長連接協(xié)議。

            Echo的作用:熟悉服務(wù)端被動接受新連接、收發(fā)數(shù)據(jù)、被動處理連接斷開。每個連接是獨立服務(wù)的,連接之間沒有關(guān)聯(lián)。在消息內(nèi)容方面Echo有一些變種:比如做成一問一答的方式,收到的請求和發(fā)送響應(yīng)的內(nèi)容不一樣,這時候要考慮打包與拆包格式的設(shè)計,進一步還可以寫簡單的HTTP服務(wù)。

            Chat的作用:連接之間的數(shù)據(jù)有交流,從a收到的數(shù)據(jù)要發(fā)給b。這樣對連接管理提出的更高的要求:如何用一個程序同時處理多個連接?fork() per connection似乎是不行的。如何防止串話?b有可能隨時斷開連接,而新建立的連接c可能恰好復(fù)用了b的文件描述符,那么a會不會錯誤地把消息發(fā)給c?

            Proxy的作用:連接的管理更加復(fù)雜:既要被動接受連接,也要主動發(fā)起連接,既要主動關(guān)閉連接,也要被動關(guān)閉連接。還要考慮兩邊速度不匹配,見《Muduo 網(wǎng)絡(luò)編程示例之十:socks4a 代理服務(wù)器》。

            這三個例子功能簡單,突出了TCP網(wǎng)絡(luò)編程中的重點問題,挨著做一遍基本就能達到層次一的要求。

            TCP的可靠性有多高?

            TCP是“面向連接的、可靠的、字節(jié)流傳輸協(xié)議”,這里的“可靠”究竟是什么意思?《Effective TCP/IP Programming》第9條說:Realize That TCP Is a Reliable Protocol, Not an Infallible Protocol,那么TCP在哪種情況下會出錯?這里說的“出錯”指的是收到的數(shù)據(jù)與發(fā)送的數(shù)據(jù)不一致,而不是數(shù)據(jù)不可達。

            我在《一種自動反射消息類型的 Google Protobuf 網(wǎng)絡(luò)傳輸方案》中設(shè)計了帶check sum的消息格式,很多人表示不理解,認為是多余的。IP header里邊有check sum,TCP header也有check sum,鏈路層以太網(wǎng)還有CRC32校驗,那么為什么還需要在應(yīng)用層做校驗?什么情況下TCP傳送的數(shù)據(jù)會出錯?

            IP header和TCP header的check sum是一種非常弱的16-bit check sum算法,把數(shù)據(jù)當(dāng)成反碼表示的16-bit integers,再加到一起。這種checksum算法能檢出一些簡單的錯誤,而對某些錯誤無能為力,由于是簡單的加法,遇到“和”不變的情況就無法檢查出錯誤(比如交換兩個16-bit整數(shù),加法滿足交換律,結(jié)果不變)。以太網(wǎng)的CRC32只能保證同一個網(wǎng)段上的通信不會出錯(兩臺機器的網(wǎng)線插到同一個交換機上,這時候以太網(wǎng)的CRC是有用的)。但是,如果兩臺機器之間經(jīng)過了多級路由器呢?

            router

            上圖中Client向Server發(fā)了一個TCP segment,這個segment先被封裝成一個IP packet,再被封裝成ethernet frame,發(fā)送到路由器(圖中消息a)。Router收到ethernet frame (b),轉(zhuǎn)發(fā)到另一個網(wǎng)段(c),最后Server收到d,通知應(yīng)用程序。Ethernet CRC能保證a和b相同,c和d相同;TCP header check sum的強度不足以保證收發(fā)payload的內(nèi)容一樣。另外,如果把Router換成NAT,那么NAT自己會構(gòu)造c(替換掉源地址),這時候a和d的payload不能用tcp header checksum校驗。

            路由器可能出現(xiàn)硬件故障,比方說它的內(nèi)存故障(或偶然錯誤)導(dǎo)致收發(fā)IP報文出現(xiàn)多bit的反轉(zhuǎn)或雙字節(jié)交換,這個反轉(zhuǎn)如果發(fā)生在payload區(qū),那么無法用鏈路層、網(wǎng)絡(luò)層、傳輸層的check sum查出來,只能通過應(yīng)用層的check sum來檢測。這個現(xiàn)象在開發(fā)的時候不會遇到,因為開發(fā)用的幾臺機器很可能都連到同一個交換機,ethernet CRC能防止錯誤。開發(fā)和測試的時候數(shù)據(jù)量不大,錯誤很難發(fā)生。之后大規(guī)模部署到生產(chǎn)環(huán)境,網(wǎng)絡(luò)環(huán)境復(fù)雜,這時候出個錯就讓人措手不及。有一篇論文《When the CRC and TCP checksum disagree》分析了這個問題。另外《The Limitations of the Ethernet CRC and TCP/IP checksums for error detection》(http://noahdavids.org/self_published/CRC_and_checksum.html)也值得一讀。

            這個情況真的會發(fā)生嗎?會的,Amazon S3 在2008年7月就遇到過,單bit反轉(zhuǎn)導(dǎo)致了一次嚴重線上事故,所以他們吸取教訓(xùn)加了 check sum。見http://status.aws.amazon.com/s3-20080720.html

            另外一個例證:下載大文件的時候一般都會附上MD5,這除了有安全方面的考慮(防止篡改),也說明應(yīng)用層應(yīng)該自己設(shè)法校驗數(shù)據(jù)的正確性。這是end-to-end principle的一個例證。

            三本必看的書

            談到Unix編程和網(wǎng)絡(luò)編程,W. Richard Stevens 是個繞不開的人物,他生前寫了6本書,APUE、兩卷UNP、三卷TCP/IP。有四本與網(wǎng)絡(luò)編程直接相關(guān)。UNP第二卷其實跟網(wǎng)絡(luò)編程關(guān)系不大,是APUE在多線程和進程間通信(IPC)方面的補充。很多人把TCP/IP一二三卷作為整體推薦,其實這三本書用處不同,應(yīng)該區(qū)別對待。

            這里談到的幾本書都沒有超出孟巖在《TCP/IP 網(wǎng)絡(luò)編程之四書五經(jīng)》中的推薦,說明網(wǎng)絡(luò)編程這一領(lǐng)域已經(jīng)相對成熟穩(wěn)定。

            · 《TCP/IP Illustrated, Vol. 1: The Protocols》中文名《TCP/IP 詳解》,以下簡稱 TCPv1。

            TCPv1 是一本奇書。

            這本書迄今至少被三百多篇學(xué)術(shù)論文引用過http://portal.acm.org/citation.cfm?id=161724。一本學(xué)術(shù)專著被論文引用算不上出奇,難得的是一本寫給程序員看的技術(shù)書能被學(xué)術(shù)論文引用幾百次,我不知道還有哪本技術(shù)書能做到這一點。

            TCPv1 堪稱 TCP/IP領(lǐng)域的圣經(jīng)。作者 W. Richard Stevens 不是 TCP/IP 協(xié)議的發(fā)明人,他從使用者(程序員)的角度,以 tcpdump 為工具,對 TCP 協(xié)議抽絲剝繭娓娓道來(第17~24章),讓人嘆服。恐怕 TCP 協(xié)議的設(shè)計者也難以講解得如此出色,至少不會像他這么耐心細致地畫幾百幅收發(fā) package 的時序圖。

            TCP作為一個可靠的傳輸層協(xié)議,其核心有三點:

            1. Positive acknowledgement with retransmission

            2. Flow control using sliding window(包括Nagle 算法等)

            3. Congestion control(包括slow start、congestion avoidance、fast retransmit等)

            第一點已經(jīng)足以滿足“可靠性”要求(為什么?);第二點是為了提高吞吐量,充分利用鏈路層帶寬;第三點是防止過載造成丟包。換言之,第二點是避免發(fā)得太慢,第三點是避免發(fā)得太快,二者相互制約。從反饋控制的角度看,TCP像是一個自適應(yīng)的節(jié)流閥,根據(jù)管道的擁堵情況自動調(diào)整閥門的流量。

            TCP的 flow control 有一個問題,每個TCP connection是彼此獨立的,保存有自己的狀態(tài)變量;一個程序如果同時開啟多個連接,或者操作系統(tǒng)中運行多個網(wǎng)絡(luò)程序,這些連接似乎不知道他人的存在,缺少對網(wǎng)卡帶寬的統(tǒng)籌安排。(或許現(xiàn)代的操作系統(tǒng)已經(jīng)解決了這個問題?)

            TCPv1 唯一的不足是它出版太早了,1993 年至今網(wǎng)絡(luò)技術(shù)發(fā)展了幾代。鏈路層方面,當(dāng)年主流的 10Mbit 網(wǎng)卡和集線器早已經(jīng)被淘汰;100Mbit 以太網(wǎng)也沒什么企業(yè)在用了,交換機(switch)也已經(jīng)全面取代了集線器(hub);服務(wù)器機房以 1Gbit 網(wǎng)絡(luò)為主,有些場合甚至用上了 10Gbit 以太網(wǎng)。另外,無線網(wǎng)的普及也讓TCP flow control面臨新挑戰(zhàn);原來設(shè)計TCP的時候,人們認為丟包通常是擁塞造成的,這時應(yīng)該放慢發(fā)送速度,減輕擁塞;而在無線網(wǎng)中,丟包可能是信號太弱造成的,這時反而應(yīng)該快速重試,以保證性能。網(wǎng)絡(luò)層方面變化不大,IPv6 雷聲大雨點小。傳輸層方面,由于鏈路層帶寬大增,TCP window scale option 被普遍使用,另外 TCP timestamps option 和 TCP selective ack option 也很常用。由于這些因素,在現(xiàn)在的 Linux 機器上運行 tcpdump 觀察 TCP 協(xié)議,程序輸出會與原書有些不同。

            一個好消息:TCPv1將于今年10月(2011年)推出第二版,Amazon 的預(yù)定頁面是:http://www.amazon.com/gp/product/0321336313,讓我們拭目以待。

            · 《Unix Network Programming, Vol. 1: Networking API》第二版或第三版(這兩版的副標題稍有不同,第三版去掉了 XTI),以下統(tǒng)稱 UNP,如果需要會以 UNP2e、UNP3e 細分。

            UNP是Sockets API的權(quán)威指南,但是網(wǎng)絡(luò)編程遠不是使用那十幾個Sockets API那么簡單,作者 W. Richard Stevens深刻地認識到這一點,他在UNP2e的前言中寫到:http://www.kohala.com/start/preface.unpv12e.html

            I have found when teaching network programming that about 80% of all network programming problems have nothing to do with network programming, per se. That is, the problems are not with the API functions such as accept and select, but the problems arise from a lack of understanding of the underlying network protocols. For example, I have found that once a student understands TCP's three-way handshake and four-packet connection termination, many network programming problems are immediately understood.

            搞網(wǎng)絡(luò)編程,一定要熟悉TCP/IP協(xié)議及其外在表現(xiàn)(比如打開和關(guān)閉Nagle算法對收發(fā)包的影響),不然出點意料之外的情況就摸不著頭腦了。我不知道為什么UNP3e在前言中去掉了這段至關(guān)重要的話。

            另外值得一提的是,UNP中文版翻譯得相當(dāng)好,譯者楊繼張先生是真懂網(wǎng)絡(luò)編程的。

            UNP很詳細,面面俱到,UDP、TCP、IPv4、IPv6都講到了。要說有什么缺點的話,就是太詳細了,重點不夠突出。我十分贊同孟巖說的

            “(孟巖)我主張,在具備基礎(chǔ)之后,學(xué)習(xí)任何新東西,都要抓住主線,突出重點。對于關(guān)鍵理論的學(xué)習(xí),要集中精力,速戰(zhàn)速決。而旁枝末節(jié)和非本質(zhì)性的知識內(nèi)容,完全可以留給實踐去零敲碎打。

            “原因是這樣的,任何一個高級的知識內(nèi)容,其中都只有一小部分是有思想創(chuàng)新、有重大影響的,而其它很多東西都是瑣碎的、非本質(zhì)的。因此,集中學(xué)習(xí)時必須把握住真正重要那部分,把其它東西留給實踐。對于重點知識,只有集中學(xué)習(xí)其理論,才能確保體系性、連貫性、正確性,而對于那些旁枝末節(jié),只有邊干邊學(xué)能夠讓你了解它們的真實價值是大是小,才能讓你留下更生動的印象。如果你把精力用錯了地方,比如用集中大塊的時間來學(xué)習(xí)那些本來只需要查查手冊就可以明白的小技巧,而對于真正重要的、思想性東西放在平時零敲碎打,那么肯定是事倍功半,甚至適得其反。

            “因此我對于市面上絕大部分開發(fā)類圖書都不滿——它們基本上都是面向知識體系本身的,而不是面向讀者的。總是把相關(guān)的所有知識細節(jié)都放在一堆,然后一堆一堆攢起來變成一本書。反映在內(nèi)容上,就是毫無重點地平鋪直敘,不分輕重地陳述細節(jié),往往在第三章以前就用無聊的細節(jié)謀殺了讀者的熱情。為什么當(dāng)年侯捷先生的《深入淺出MFC》和 Scott Meyers 的 Effective C++ 能夠成為經(jīng)典?就在于這兩本書抓住了各自領(lǐng)域中的主干,提綱挈領(lǐng),綱舉目張,一下子打通讀者的任督二脈。可惜這樣的書太少,就算是已故 Richard Stevens 和當(dāng)今 Jeffrey Richter 的書,也只是在體系性和深入性上高人一頭,并不是面向讀者的書。”

            什么是旁枝末節(jié)呢?拿以太網(wǎng)來說,CRC32如何計算就是“旁枝末節(jié)”。網(wǎng)絡(luò)程序員要明白check sum的作用,知道為什么需要check sum,至于具體怎么算CRC就不需要程序員操心。這部分通常是由網(wǎng)卡硬件完成的,在發(fā)包的時候由硬件填充CRC,在收包的時候網(wǎng)卡自動丟棄CRC不合格的包。如果代碼里邊確實要用到CRC計算,調(diào)用通用的zlib就行,也不用自己實現(xiàn)。

            UNP就像給了你一堆做菜的原料(各種Sockets 函數(shù)的用法),常用和不常用的都給了(Out-of-Band Data、Signal-Driven IO 等等),要靠讀者自己設(shè)法取舍組合,做出一盤大菜來。在第一遍讀的時候,我建議只讀那些基本且重要的章節(jié);另外那些次要的內(nèi)容可略作了解,即便跳過不讀也無妨。UNP是一本操作性很強的書,讀這本這本書一定要上機練習(xí)。

            另外,UNP舉的兩個例子(菜譜)太簡單,daytime和echo一個是短連接協(xié)議,一個是長連接無格式協(xié)議,不足以覆蓋基本的網(wǎng)絡(luò)開發(fā)場景(比如 TCP封包與拆包、多連接之間交換數(shù)據(jù))。我估計 W. Richard Stevens 原打算在 UNP第三卷中講解一些實際的例子,只可惜他英年早逝,我等無福閱讀。

            UNP是一本偏重Unix傳統(tǒng)的書,這本書寫作的時候服務(wù)端還不需要處理成千上萬的連接,也沒有現(xiàn)在那么多網(wǎng)絡(luò)攻擊。書中重點介紹的以accept()+fork()來處理并發(fā)連接的方式在現(xiàn)在看來已經(jīng)有點吃力,這本書的代碼也沒有特別防范惡意攻擊。如果工作涉及這些方面,需要再進一步學(xué)習(xí)專門的知識(C10k問題,安全編程)。

            TCPv1和UNP應(yīng)該先看哪本?我不知道。我自己是先看的TCPv1,花了大約半學(xué)期時間,然后再讀UNP2e和APUE。

            · 《Effective TCP/IP Programming

            第三本書我猶豫了很久,不知道該推薦哪本,還有哪本書能與 W. Richard Stevens 的這兩本比肩嗎?W. Richard Stevens 為技術(shù)書籍的寫作樹立了難以逾越的標桿,他是一位偉大的技術(shù)作家。沒能看到他寫完 UNP 第三卷實在是人生的遺憾。

            Effective TCP/IP Programming》這本書屬于專家經(jīng)驗總結(jié)類,初看時覺得收獲很大,工作一段時間再看也能有新的發(fā)現(xiàn)。比如第6 條“TCP是一個字節(jié)流協(xié)議”,看過這一條就不會去研究所謂的“TCP粘包問題”。我手頭這本電力社2001年的中文版翻譯尚可,但是很狗血的是把參考文獻去掉了,正文中引用的文章資料根本查不到名字。人郵2011年重新翻譯出版的版本有參考文獻。

            其他值得一看的書

            以下兩本都不易讀,需要相當(dāng)?shù)幕A(chǔ)。

            · 《TCP/IP Illustrated, Vol. 2: The Implementation》以下簡稱 TCPv2

            1200頁的大部頭,詳細講解了4.4BSD的完整TCP/IP協(xié)議棧,注釋了15,000行C源碼。這本書啃下來不容易,如果時間不充裕,我認為沒必要啃完,應(yīng)用層的網(wǎng)絡(luò)程序員選其中與工作相關(guān)的部分來閱讀即可。

            這本書第一作者是Gary Wright,從敘述風(fēng)格和內(nèi)容組織上是典型的“面向知識體系本身”,先講mbuf,再從鏈路層一路往上、以太網(wǎng)、IP網(wǎng)絡(luò)層、ICMP、IP多播、IGMP、IP路由、多播路由、Sockets系統(tǒng)調(diào)用、ARP等等。到了正文內(nèi)容3/4的地方才開始講TCP。面面俱到、主次不明。

            對于主要使用TCP的程序員,我認為TCPv2一大半內(nèi)容可以跳過不看,比如路由表、IGMP等等(開發(fā)網(wǎng)絡(luò)設(shè)備的人可能更關(guān)心這些內(nèi)容)。在工作中大可以把IP視為host-to-host的協(xié)議,把“IP packet如何送達對方機器”的細節(jié)視為黑盒子,這不會影響對TCP的理解和運用,因為網(wǎng)絡(luò)協(xié)議是分層的。這樣精簡下來,需要看的只有三四百頁,四五千行代碼,大大減輕了負擔(dān)。

            這本書直接呈現(xiàn)高質(zhì)量的工業(yè)級操作系統(tǒng)源碼,讀起來有難度,讀懂它甚至要有“不求甚解的能力”。其一,代碼只能看,不能上機運行,也不能改動試驗。其二,與操作系統(tǒng)其他部分緊密關(guān)聯(lián)。比如TCP/IP stack下接網(wǎng)卡驅(qū)動、軟中斷;上承inode轉(zhuǎn)發(fā)來的系統(tǒng)調(diào)用操作;中間還要與平級的進程文件描述符管理子系統(tǒng)打交道;如果要把每一部分都弄清楚,把持不住就迷失主題了。其三,一些歷史包袱讓代碼變復(fù)雜晦澀。比如BSD在80年代初需要在只有4M內(nèi)存的VAX上實現(xiàn)TCP/IP,內(nèi)存方面捉襟見肘,這才發(fā)明了mbuf結(jié)構(gòu),代碼也增加了不少偶發(fā)復(fù)雜度(buffer不連續(xù)的處理)。

            讀這套TCP/IP書切忌膠柱鼓瑟,這套書以4.4BSD為底,其描述的行為(特別是與timer相關(guān)的行為)與現(xiàn)在的Linux TCP/IP有不小的出入,用書本上的知識直接套用到生產(chǎn)環(huán)境的Linux系統(tǒng)可能會造成不小的誤解和困擾。(TCPv3不重要,可以成套買來收藏,不讀亦可。)

            · 《Pattern-Oriented Software Architecture Volume 2: Patterns for Concurrent and Networked Objects》以下簡稱POSA2

            這本書總結(jié)了開發(fā)并發(fā)網(wǎng)絡(luò)服務(wù)程序的模式,是對UNP很好的補充。UNP中的代碼往往把業(yè)務(wù)邏輯和Sockets API調(diào)用混在一起,代碼固然短小精悍,但是這種編碼風(fēng)格恐怕不適合開發(fā)大型的網(wǎng)絡(luò)程序。POSA2強調(diào)模塊化,網(wǎng)絡(luò)通信交給library/framework去做,程序員寫代碼只關(guān)注業(yè)務(wù)邏輯,這是非常重要的思想。閱讀這本書對于深入理解常用的event-driven網(wǎng)絡(luò)庫(libevent、Java Netty、Java Mina、Perl POE、Python Twisted等等)也很有幫助,因為這些庫都是依照這本書的思想編寫的。

            POSA2的代碼是示意性的,思想很好,細節(jié)不佳。其C++ 代碼沒有充分考慮資源的自動化管理(RAII),如果直接按照書中介紹的方式去實現(xiàn)網(wǎng)絡(luò)庫,那么會給使用者造成不小的負擔(dān)與陷阱。換言之,照他說的做,而不是照他做的學(xué)。

            不值一看的書

            Douglas Comer 教授名氣很大,著作等身,但是他寫的網(wǎng)絡(luò)方面的書不值一讀,味同嚼蠟。網(wǎng)絡(luò)編程與 TCP/IP 方面,有W. Richard Stevens 的書扛鼎;計算機網(wǎng)絡(luò)原理方面,有Kurose的“自頂向下”和Peterson的“系統(tǒng)”打旗,沒其他人什么事兒。順便一提,Tanenbaum的操作系統(tǒng)教材是最好的之一(嗯,之二,因為他寫了兩本:“現(xiàn)代”和“設(shè)計與實現(xiàn)”),不過他的計算機網(wǎng)絡(luò)和體系結(jié)構(gòu)教材的地位比不上他的操作系統(tǒng)書的地位。體系結(jié)構(gòu)方面,Patterson 和 Hennessy二人合作的兩本書是最好的,近年來嶄露頭角的《深入理解計算機系統(tǒng)》也非常好;當(dāng)然,側(cè)重點不同。

            (完)

            posted on 2011-06-06 08:44 陳碩 閱讀(60111) 評論(14)  編輯 收藏 引用 所屬分類: muduo

            評論

            # re: 談一談網(wǎng)絡(luò)編程學(xué)習(xí)經(jīng)驗 2011-06-06 11:55 treapdb

            果斷收藏。  回復(fù)  更多評論   

            # re: 談一談網(wǎng)絡(luò)編程學(xué)習(xí)經(jīng)驗 2011-06-06 14:57 千暮(zblc)

            mark!  回復(fù)  更多評論   

            # re: 談一談網(wǎng)絡(luò)編程學(xué)習(xí)經(jīng)驗 2011-06-06 20:45 nomagic

            我也覺得ACE搞得過于復(fù)雜了,小問題多多。學(xué)習(xí)一下它的某些思路和模式應(yīng)該還是有些意義的,可以開闊思路,海納百川。但是把ACE用于實際項目基本是自找麻煩。  回復(fù)  更多評論   

            # re: 談一談網(wǎng)絡(luò)編程學(xué)習(xí)經(jīng)驗 2011-06-06 22:12 陳梓瀚(vczh)

            @nomagic
            那其實就是一個科學(xué)家做的demo吧,如果你仔細觀察那些開發(fā)者的來源……  回復(fù)  更多評論   

            # re: 談一談網(wǎng)絡(luò)編程學(xué)習(xí)經(jīng)驗 2011-06-06 22:23 jigsaw

            服了你了。mbuf在你嘴里成了剩飯剩菜。

            你除了Linux的TCP層,你還看過哪些TCP stack?你知不知道絕大多數(shù)_閉源_的TCP stack都是基于mbuf的?不管是低端手持設(shè)備還是高端的路由器,只要不是基于Linux的,一定是基于mbuf的TCP stack。
            Linux的skbuf也是處處有mbuf的影子-盡管Linus說他是從頭寫過的。
            我懷疑你連Linux的TCP stack都沒看過吧?

            剛說完基礎(chǔ)的重要性,轉(zhuǎn)口又嫌TCPv2太難,還是不求甚解的好 - 這就是博主的態(tài)度。

              回復(fù)  更多評論   

            # re: 談一談網(wǎng)絡(luò)編程學(xué)習(xí)經(jīng)驗 2011-06-07 09:55 zuhd

            我主張,在具備基礎(chǔ)之后,學(xué)習(xí)任何新東西,都要抓住主線,突出重點。對于關(guān)鍵理論的學(xué)習(xí),要集中精力,速戰(zhàn)速決。而旁枝末節(jié)和非本質(zhì)性的知識內(nèi)容,完全可以留給實踐去零敲碎打。

            這點我要好好學(xué)習(xí)下  回復(fù)  更多評論   

            # re: 談一談網(wǎng)絡(luò)編程學(xué)習(xí)經(jīng)驗[未登錄] 2011-06-07 14:04 vincent

            tcpv2很難看下去
            不知為何,也不知從何時起越來越不喜歡厚重的書了  回復(fù)  更多評論   

            # re: 談一談網(wǎng)絡(luò)編程學(xué)習(xí)經(jīng)驗(06-08更新) 2011-06-09 14:38 ISO

            jigsaw,和陳碩的水平在我眼中都是小菜一碟, 我不但通讀rfc各種文檔,還深入研究過bsd, linux tcp/ip protocol implementation, 對鏈路層更是了如指掌,對各種硬件的電子電器特性也很精通。你們都是菜鳥,我的服務(wù)器可以并發(fā)處理上億的tcp.  回復(fù)  更多評論   

            # re: 談一談網(wǎng)絡(luò)編程學(xué)習(xí)經(jīng)驗(06-08更新) 2011-06-09 16:36 陳碩

            @ISO
            佩服佩服!  回復(fù)  更多評論   

            # re: 談一談網(wǎng)絡(luò)編程學(xué)習(xí)經(jīng)驗(06-08更新) 2011-06-10 15:48 千暮(zblc)

            @ISO
            求blog............  回復(fù)  更多評論   

            # re: 談一談網(wǎng)絡(luò)編程學(xué)習(xí)經(jīng)驗(06-08更新) 2011-06-10 17:08 jc_ontheroad

            網(wǎng)絡(luò)編程,學(xué)習(xí)中。  回復(fù)  更多評論   

            # re: 談一談網(wǎng)絡(luò)編程學(xué)習(xí)經(jīng)驗(06-08更新) 2011-09-19 14:50 see

            TCP/IP and IMS Sequence Diagrams
            www.eventhelix.com/RealtimeMantra/Networking  回復(fù)  更多評論   

            # re: 談一談網(wǎng)絡(luò)編程學(xué)習(xí)經(jīng)驗(06-08更新)[未登錄] 2011-12-22 13:48 Chipset

            Linux Kernel也大量用到了動態(tài)內(nèi)存分配。既然操作系統(tǒng)內(nèi)核都不怕動態(tài)分配內(nèi)存造成碎片,應(yīng)用程序為什么要害怕?

            暈,什么時候操作系統(tǒng)都不怕碎片啦?linux內(nèi)核原來用buddy,2.2以后來用slab因為啥原因啊?類似情況還有FreeBSD5.0, NetBSD4.0和Solaris2.4以后。  回復(fù)  更多評論   

            # re: 談一談網(wǎng)絡(luò)編程學(xué)習(xí)經(jīng)驗(06-08更新)[未登錄] 2011-12-22 13:51 Chipset

            Douglas Comer也得罪你啦,講點道理行不?  回復(fù)  更多評論   

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

            導(dǎo)航

            統(tǒng)計

            常用鏈接

            隨筆分類

            隨筆檔案

            相冊

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            日韩人妻无码一区二区三区久久99| 亚洲av日韩精品久久久久久a| 无码人妻久久一区二区三区免费丨| 久久久久亚洲精品中文字幕| 99久久人人爽亚洲精品美女| 久久久久国产一级毛片高清版| A狠狠久久蜜臀婷色中文网| 亚洲国产精品无码久久一线 | 久久久久久免费一区二区三区| 久久亚洲AV成人无码电影| 青草国产精品久久久久久| 久久天堂AV综合合色蜜桃网| 久久久无码人妻精品无码| 久久久女人与动物群交毛片| 国产美女久久精品香蕉69| 99久久精品国产免看国产一区| 久久久久一区二区三区| 久久精品国产亚洲7777| 久久久久久午夜精品| 国产成人久久AV免费| 国产亚洲美女精品久久久| 香蕉aa三级久久毛片| 久久久久人妻一区精品性色av| 久久久久一区二区三区| 久久综合一区二区无码| 漂亮人妻被黑人久久精品| 久久精品视频免费| 久久中文字幕人妻丝袜| 色综合久久综精品| 亚洲国产婷婷香蕉久久久久久| 久久久久亚洲AV成人片| 青春久久| 久久99中文字幕久久| 亚洲午夜福利精品久久| 久久国产精品成人免费| 欧美亚洲国产精品久久高清| 色综合久久最新中文字幕| 久久AV高潮AV无码AV| 久久国产精品视频| 国产精品久久久久影院嫩草| 久久无码AV中文出轨人妻|