個人網絡開發之旅——socket編程

上一篇文章《TCP/IP協議分析》講述了本身是如何和網絡領域的開發扯上關係的。正如從招聘網站上抽出的幾個關鍵詞「TCP/IP, Socket, 多線程」可見,協議分析並非網絡開發的主流,一般咱們所說的網絡編程是socket編程。今天就以個人經從來講一下socket編程的相關知識。html


socket編程的基礎知識我就不在這裏科普了,你們能夠經過相關書籍和資料去了解。
python

socket編程難嗎

在招聘工程師時面試問到某些新人這個問題。他們覺得會編寫客戶端/服務端創建鏈接正常收發數據的流程就認爲本身瞭解socket開發。真是這樣簡單調用幾個API,理解下三次握手,會使用bind、listen、......就能夠了嗎?linux

固然不是,隨着客戶端數量的增長,少許併發——>大量併發——>海量併發的過程當中服務端的處理難度也會隨之增長。在服務端編程中很是有名的C10K問題(網絡服務在處理數以萬計的客戶端鏈接時,每每出現效率低下甚至徹底癱瘓)就向咱們作了很詳細的說明。可是客戶端socket編程雖然沒有這種併發要求就必定簡單嗎?我認爲不是的。請參看個人這篇文章《客戶端網絡庫實現真的很簡單嗎》。另外互聯網中各類複雜的網絡環境也會給咱們進行socket編程帶來不少困難和挑戰。git

因此整體來講想要作好socket編程仍是有必定難度的。你們很容易從各類招聘渠道瞭解到精通這個領域的人在市場上很熱銷,報酬也很可觀,並且多爲一些互聯網巨頭和新興互聯網公司所須要。github

服務端的網絡模型

要想處理咱們上面所說的C10K甚至C100K問題,網絡模型的選擇是很是重要的。那麼咱們首先要清楚幾個概念:阻塞I/O,非阻塞I/O,I/O複用,異步I/O 。網絡上關於這個話題的討論有不少,我說說個人理解吧:面試

  • 阻塞/非阻塞:進程/線程要訪問的數據是否就緒,進程/線程是否須要睡眠等待。編程

  • 同步/異步:訪問數據的方式,同步須要主動讀寫數據,在讀寫數據的過程當中仍是會阻塞。異步只須要獲得I/O操做完成的通知,並不主動讀寫數據,而是由操做系統去完成數據的讀寫。json

因此能夠看出阻塞I/O,非阻塞I/O,I/O複用都屬於同步的範疇。windows

常見的幾種服務端網絡模型:設計模式

  • all connections one thread+blocking I/O:服務端對全部客戶端鏈接只用一個線程去處理。並且網絡I/O仍是阻塞的。這在多併發狀況下就是找死,吞吐率會很低,延遲會很是大。

  • per connection per thread+blocking I/O:服務端線程資源是有限的,並且線程的上下文切換是很耗資源的,隨着客戶端併發鏈接的增多系統資源也會慢慢吃緊。可是在這種模型的基礎上,有些語言內置的協程(用戶級線程)卻能夠解決資源問題。好比Go routine, Erlang actor。前幾天剛發現了一個基於C語言的協程庫state thread也能夠用來實現用戶級線程。

  • thread pool+blocking I/O:線程池的方式依然會受制於服務器CPU個數,天然也不會高效的。

  • non-blocking I/O + I/O multiplexing:網絡I/O的多路複用,正是解決C10K問題最基礎的方案。可是還能夠進一步優化嗎?

  • non-blocking I/O + I/O multiplexing + asyc I/O:很是理想、高效的網絡模型。windows下是利用完成端口來幫咱們實現這個模型,linux下要依賴異步I/O機制,可是到底是否好用我沒嘗試過。

從上面又引出了兩種高性能的服務端網絡編程設計模式:基於I/O事件驅動的Reactor和基於異步I/O驅動的Proactor。其中non-blocking I/O + I/O multiplexing屬於Reactor模式。non-blocking I/O + I/O multiplexing + asyc I/O屬於Proactor模式。

重點介紹下non-blocking I/O + I/O multiplexing

今天咱們所講的只基於linux平臺。畢竟linux平臺的服務器佔據了市場份額的90%以上。linux下目前最成熟的模型是epoll。(說到這給你們提個問題:epoll和它的老前輩select有什麼不一樣呢?)

剛纔講到non-blocking I/O + I/O multiplexing時,提到過在此模型的基礎上咱們還能夠優化嗎?能夠的。咱們能夠採用一個線程對應一個事件循環的機制啓用多個線程。畢竟如今的服務器硬件資源是很強大的,咱們不要浪費了多cpu資源。這就引出了咱們要講的另外一個概念:master—worker模型。字面上的理解就是有一個master負責協調工做,由好幾個worker去實際完成工做。在這種編程模型中:也就是有一個master負責將客戶端鏈接分發給不一樣的worker線程,或者通知鏈接來了由worker去搶佔,實際上由worker去完成客戶端鏈接的讀寫或邏輯處理工做。這樣不但有效利用了服務器的CPU資源,也增長了服務端的吞吐量,下降了客戶端的延遲。更詳細的講解請參見個人文章《從master-worker模型看團隊管理》 。

一些知名的第三方網絡庫

站在巨人的肩膀上可讓咱們看得更爲高遠,若是選用了合適的第三方網絡庫也會使咱們的工做事半功倍。

  • ACE學之者生用之者死。這是陳碩老師對ACE庫的評價,我以爲很形象。對於學院派理想化的東西去學習收益很大,可是使用就不見得適合本身。

  • boost asio:has a 「near STL」 status;

  • Poco: 很全面的庫不只僅有網絡庫。

  • libev :速度更快,bug更少,特性更多,體積更小;

  • libevent:簡單,強大;

網絡協議選則

網絡編程中還有很重要的一點是客戶端/服務端交互數據協議的選擇。咱們選擇的依據有哪些呢?

  1. 網絡數據大小——佔用帶寬,傳輸效率;

  2. 網絡數據安全性——敏感數據的網絡安全;

  3. 編碼複雜度——序列化和反序列化複雜度,效率,數據結構的可擴展性,可 維護性;

  4. 協議通用性——大衆規範;

  • 咱們能夠以自定義的角度採用TLV結構的二進制協議

  • 能夠以提供序列化和反序列化庫的的角度採用第三方協議:protocol buffers, json, thrift

  • 能夠以選擇文本化協議的角度選擇xml,json協議。

個人理解是什麼呢?請參見文章《網絡傳輸數據格式的選擇》

實踐中你還經常會遇到

關鍵詞MTU、SO_LINGER、TCPNODELAY、TIMEWAIT、keepalive、串話...這些關鍵詞都表明了某種你須要考慮和處理的網絡狀況。

輔助工具python、netcat、tcpdump、wireshark...它們都會成爲使你事半功倍的巨人。

推薦書籍:

《UNIX網絡編程卷1》
《Linux多線程服務端編程》
《構建高性能Web站點》

參考資料

《UNIX網絡編程卷1》
《Linux多線程服務端編程》
http://stackoverflow.com/questions/992069/ace-vs-boost-vs-pocohttp://stackoverflow.com/questions/9433864/whats-the-difference-between-libev-and-libevent

個人github項目

高性能tcp網絡服務器

基於TCP協議的遠程過程調用框架客戶端實現

相關文章
相關標籤/搜索