Java的網絡程式設計如果不是專門搞伺服器性能開發或者消息分發,幾乎可能涉及不到。但是它卻是面試找工作必問的一個知識點,涵蓋的知識體系也非常廣泛,從Java底層IO原理到作業系統核心組成,再到網絡TCP、UDP、HTTP的應用實踐....是以,即便是職場多年的老油條,仍然需要時刻複習,更别提我這種隻有七秒鐘記憶的小菜鳥了。
Java網絡IO的演化,從最開始JDK1.4之前是基于阻塞的IO;發展到1.4釋出後的Nio提供了selector多路複用的機制以及channel和buffer,再到1.7的NIO更新提供了真正的異步api;再發展到後來嶄露頭角的MINA和Netty。是以整個網絡IO程式設計的學習整理,也會按照下面的幾個步驟來進行:
- 網絡IO的基本知識與概念
- 普通IO以及BIO伺服器
- NIO的使用與伺服器Hello world
- Netty的使用與伺服器Hello world
今天就簡單的了解下網絡IO需要具備的基本知識與概念。
同步、異步和阻塞、非阻塞
經常聽人提起,同步阻塞伺服器或者異步非阻塞伺服器,網上有很多的文章針對這個概念作出了講解,每個人了解的貌似都不太一樣。最容易把異步和非阻塞搞混....我這裡簡單的說下自己的了解:
同步synchronous、異步asynchronous,他們的差別就是發起任務後,本身的一個狀态——如果是一直等待結果,那就是同步;如果立即傳回,并采用其他的方式得到結果就是異步(比如,狀态、通知、回調)。
舉個例子:
- 在過去科技不發達的時候,銀行取錢都是排隊的模式。想取錢就得去排隊,直到輪到自己,這就是同步;
- 現在去銀行一般直接叫号,然後去休息位置休息打遊戲,登到輪到自己的時候,會有通知,這就是異步;
阻塞blocking、非阻塞non-blocking,則聚焦的是CPU在等待結果的過程中的狀态。比如前面的例子,排隊的過程中什麼也不做就是阻塞;一邊排隊,一遍玩王者榮耀就是非阻塞的。
使用者空間與内和空間
這個概念就涉及作業系統了,為了保護作業系統的安全,會将記憶體分為使用者空間和核心空間兩個部分。如果使用者想要操作核心空間的資料,需要把資料從内和空間拷貝到使用者控件。

伺服器接收用戶端發過來的請求,想要進行處理,大緻會經過下面幾個步驟:
- 伺服器的網絡驅動接收到消息,去核心上申請空間;并等待完整的資料包到達(有可能分組傳送,沒傳完...),複制到核心空間;
- 資料從核心空間拷貝到使用者空間
- 使用者程式進行處理
是以大緻可以把接收消息了解為兩個階段:1. 等待資料到達 2. 拷貝到使用者空間
了解了這個過程,就能明白為什麼會出現經典的5大網絡模型了.
五大網絡模型
這幾個網絡模型還是學生時代的時候也看過,但是了解的不夠透徹,也不知道到底有什麼差別。最近網上也看過不少的文章,發現有一些文章引用的小例子不錯,能很簡單的了解這些模型的意思。是以我這邊也借鑒一下:
在大連高新萬達後面有一條叫做金街的小吃街,有一個露天的路邊攤叫做“小紅旗”,主要是做炸臭豆腐和冷面,然後用冷面把臭豆腐卷起來,刷上臭烘烘的醬料,非常好吃。每次路過都能看到不少人在排隊,隊伍長的有種想讓人辭職加盟的感覺....基本上排個隊伍都得半個小時-一個小時吧。
這個排隊的過程,明顯就是上面所說的同步阻塞模式....那我這邊就設想下,如果小紅旗的生意做大了,可以怎麼發展?正好套用下網絡模型的概念...
1. 同步阻塞IO
這個就不詳細說了,排隊的過程哪也去不了,如果你還沒有帶手機,排隊的過程中就隻能幹瞪眼了。這就是很明顯的同步+阻塞模式。
2. 同步非阻塞IO
如果小紅旗的老闆搞了一個點菜機,來點單的顧客把自己想吃的劃上,然後等着老闆去做,自己可以在這一個小時的時間裡去周圍商場溜達下。但是由于沒有任何通信方式,隻能不停的回來問老闆,做好了沒有。
回來詢問的時間是由顧客自己掌控的,如果時間很短,那麼可以盡量早的知道臭豆腐炸好沒,但是也會影響逛街的體驗;如果時間很長,有可能臭豆腐早就做好了..結果放的時間長了,反而不好吃了。
是以非阻塞IO基于狀态輪訓的方式,雖然能讓程式在等待的過程中做點其他的事情,但是頻繁的切換運作程式,反而會造成很大的壓力。
3. IO多路複用/事件驅動
小紅旗老闆更新了系統,放棄使用點菜機,改用麥當勞那種點餐大屏。同樣是點餐,但是一個大屏裡面顯示了很多人的臭豆腐進度,即節省了資源,也避免大家不停的詢問。
其實Nio活着Netty就是基于這種模式,一個線程就可以監聽很多IO操作,這樣在IO等待上就高效多了。具體實作是依賴于作業系統的,windows和linux都有不同的實作方式。最初的select或者poll,都有并發數的限制,并且NIO的select還有空輪訓的問題;epool則突破了連接配接數的限制,一個線程就可以監聽大量的IO操作。這個感興趣的朋友,可以深入了解下select、poll、epool的原理。
4. 信号驅動IO
小紅旗老闆又時髦了,搞了一個更新版的美味不用等。顧客基于微信小程式點菜,菜做好了自動提醒顧客取餐....這個提醒的過程,就像是發射了一個特殊的信号。
不過UNIX網絡程式設計裡面的信号驅動,可沒這麼簡單,這個信号是依賴于作業系統底層的,捕獲信号或者處理都很麻煩,是以現在應用的也不是很廣泛。
5. 異步非阻塞IO
一對小情侶李雷和韓梅梅,韓梅梅口味很重,特别喜歡吃臭豆腐,但是李雷完全不感興趣,聞到味道就想吐。于是李雷就跟韓梅梅約定,讓韓梅梅自己去吃,李雷跑到旁邊的咖啡廳喝咖啡。韓梅梅自己去排隊買臭豆腐,買完順便吃完,然後回來找李雷....
這個過程就是異步非阻塞的,消息的等待和處理都在伺服器端完成,使用者隻要最後接收到消息處理完的通知就行了。
總結
總結來說,這幾種網絡模型:
- 同步阻塞:強調的是我要做! —— 别的啥也别說,就是要做!
- 同步非阻塞:強調的是我想做! —— 在想的過程中,幹點其他的事情更好。
- 異步非阻塞:強調的是我做完了!—— 等得到結果通知的時候,工作已經做完了。
其中細節,還需慢慢體會...後面的文章将會挑幾個模型做代碼的示範,更多内容還請持續關注。
參考
- 并發程式設計網
- Netty源碼分析
- IO多路複用之select、poll、epoll
- 聊聊Linux五種IO模型
- 聊聊同步、異步、阻塞、非阻塞
- Netty官方文檔
- 一篇文章,讀懂Netty的高性能架構之道
- 代碼示例分享
作者:xingoo
出處:http://www.cnblogs.com/xing901022
本文版權歸作者和部落格園共有。歡迎轉載,但必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接!