1. 什麼是Netty?

Netty是一個高性能事件驅動,非同步非阻塞的IO Java開源框架,由Jboss提供,用於建立Tcp等底層的鏈接,基於Netty可以建立高性能的Http伺服器,快速開發高性能、高可靠的網路伺服器和客戶端程序。它支持Http,websocket,tcp,udp等協議。同時Netty又是基於NIO的客戶端,伺服器端編程框架,使用Netty可以確保快速和簡單的開發出一個網路應用。例如實現了某種協議的客戶端服務端應用。Netty簡化了網路應用的開發過程,比如tcp,udp的socket服務開發。同時Netty提供了非常可靠的穩定性和良好的伸縮性。

2. Netty使用場景

高性能領域:比如遊戲,大數據分散式計算得以廣泛應用

多線程並發領域:多路復用模型,多線程模型,主從多線程模型

非同步通信領域等。

3. Java IO通信

在介紹WebSocket之前,我們先簡單說一下Java IO通信中的BIO,偽非同步IO,NIO以及AIO等。

(1)BIO通信

BIO通信:採用BIO模型通信的服務端,通常由一個獨立的線程負責監聽客戶端的連接,它接收到客戶端連接請求之後,會對每個客戶端創建一個新的線程,進行鏈路處理,處理完成之後通過輸出流返回應答給客戶端,此時線程銷毀,這就是典型的」一請求一應答「的通信模型。

該模型的最大缺點就是:缺乏彈性伸縮能力,當客戶端並發訪問量增加以後,服務端的線程個數和客戶端的並發訪問數會成1比1的正比關係,由於線程是Java虛擬機的寶貴系統資源,當線程數膨脹之後,系統的性能就會快速下降。隨著並發訪問量的繼續增大,系統將會發生線程堆棧異常或創建線程失敗等問題。最終導致進程宕機或將死,不能對外提供服務。

BIO通信模型如下圖:

客戶端的個數與服務端的線程呈1比1的正比關係

(2)偽非同步IO通信

偽非同步IO通信:當有新的客戶端接入的時候,將客戶端的socket封裝成一個task投遞到後端的線程池進行處理,線程池維護一個消息隊列和N個活躍的線程,對消息隊列中的任務進行相關的處理。也就是說當有M個客戶端接入的時候,服務端將會創建一個具有N個線程的線程池來對客戶端的請求進行處理。由於線程池可以設置消息隊列的大小和最大線程數,因此它的資源佔用是可控的,無論多少個客戶端對它訪問,都不會導致資源的耗盡和宕機。

缺點:當有大量的客戶端進入的時候,隨著並發訪問量的不斷增加,偽非同步IO通信可能會出現線程池阻塞問題。

偽非同步IO的通信模型如下圖:

當有N個新的客戶端接入的時候,偽非同步IO通信將客戶端的socket封裝成一個Task投遞到後端的線程池中進行處理,JDK的線程池負責維護一個消息隊列和N個活躍的線程,它與BIO通信模型最大的不同點是:偽非同步IO通信的服務端不再針對每一個客戶端都創建一個獨立的線程,它是由一個線程池來統一處理所有客戶端的接入請求。當有大量客戶端接入的時候,並發量不斷上漲,將會出現線程池阻塞問題。

(3)NIO通信

緩存區Buffer: 它是一個對象,它包含一些要寫入或要讀出的數據,在NIO中加入Buffer對象,體現了新庫與原IO的重要區別。在面向流的IO中,可以將數據直接寫入或者將數據直接讀到Strem對象中。在NIO中,所有數據都是用緩衝區進行處理的,在讀取數據時,直接取讀緩衝區中的數據,在寫入數據時,直接寫入緩衝區中。任何時候處理NIO中的數據時都是通過緩衝區進行操作。

通道Channel: 網路數據通過通道Channel讀取和寫入,通道與流的不同之處在於通道是雙向的,而流只是在一個方向上移動,一個流必須是InputStream或OutputStream的子類,而通道可以用於讀寫或二者同時進行。

多路復用器selector: selector提供了選擇已經就緒的任務的能力,會通過不斷輪詢在其上的Channel,在某個Channel上面發生讀或者寫事件,則該Channel處於就緒狀態,會被Selector輪詢出來,然後獲取Channel的集合進行後續IO的操作。

NIO通信並沒有最大連接數的限制,可以接入成千上萬的客戶端。

(4)AIO通信

AIO通信:它是連接註冊讀寫事件和回調函數,讀寫方法非同步,同時它是主動通知程序。AIO非同步通信提供了兩種方式獲取操作結果:第一種方式是通過java.util.concurrent的Future類來表示非同步操作的結果;第二種方式是在執行非同步操作的時候傳入一個java.nio.channels.CompletionHandler介面的實現類作為操作完成回調。NIO的非同步套接字回調,是真正的非同步非阻塞IO,對應於Unix網路編程中的事件驅動IO,不需要通過多路復用器對被註冊的通道進行輪詢操作即可實現非同步讀寫,從而簡化NIO的編程模型。

BIO,偽非同步IO,NIO, AIO之間的區別如下表:

註:客戶端個數中的比值是客戶端的個數與服務端的IO線程數的個數比

4. WebSocket

(1) 什麼是WebSocket?

WebSocket是一種H5協議規範,通過握手機制客戶端與伺服器之間就能夠建立一個類似Tcp的連接,從而方便客戶端與伺服器之間的通信。

它是一種解決客戶端與服務端實時通信而產生的技術:WebSocket本質是一種基於TCP協議,先通過Http/Https發一個特殊的Http請求進行握手,握手後會創建一個用於交換數據的TCP鏈接,之後客戶端和服務端使用該TCP鏈接進行實時通信。當WebSocket的客戶端和服務端握手後 , 也就是建立通信後,就不再需要之前的http請求參與。

(2) WebSocket的優點:

a. 節省通信開銷,之前WebServer實現通信,都使用輪詢(每隔特定時間間隔瀏覽器自動發送Http請求,去獲取服務端的響應)該情況下,需要不停的向伺服器發送請求,而HttpRequest的handler很長,請求包含真正的數據可能很小,會佔用很多額外的帶寬和伺服器資源。

b. 伺服器主動傳送數據給客戶端,在給定時間,伺服器和客戶端在任意時刻相互推送信息,瀏覽器(客戶端)和伺服器只需要做一個握手的動作。建立連接後,伺服器可主動傳數據給客戶端,客戶端也可以隨意向服務端傳數據。交換數據時所攜帶的頭信息很小。

c. 實時通信:WebSocket不僅限於Ajax方式通信。ajax方式需要瀏覽器發起請求。而WebSocket技術 服務端和客戶端可以彼此相互推送信息,從而實現實時通信。

(3) WebSocket建立連接過程步驟如下

a、客戶端發起握手請求。

b、服務端響應請求。

c、建立連接。

詳細流程:

建立一個WebSocket連接,客戶端或瀏覽器首先向伺服器發送一個特殊的Http請求(攜帶一些附加頭信息)Upgrade:websocket,服務端解析附加頭信息,產生應答消息,然後響應給客戶端,之後客戶端就與服務端建立響應的鏈接。

(4) WebSocket生命週期

1、打開事件:端點上建立新鏈接時,該事件是先於其他任何事件發生之前。該事件發生會產生三部分信息。

1.1、創建WebSocket Session對象:用於表示已經建立好的鏈接 。

1.2、配置對象:包含配置端點的信息。

1.3、一組路徑參數,用於打開節點握手時,WebSocket端入棧匹配的URI 。

2、消息事件:主要是接收WebSocket對話中,另一端發送的消息。鏈接上的消息將會有三種形式抵達客戶端。

2.1、文本消息: 用String處理

2.2、二進位消息: 用byteBuffer或者byte[]處理

2.3、pong消息: 用Java WebSocket API中的pong.message介面的實例來處理

3、錯誤事件:WebSocket鏈接或者端點發生錯誤時產生。可以處理入棧消息時發生的各種異常。入棧消息可能產生的三種異常。

3.1、WebSocket建立鏈接時發生錯誤:SessionException類型。

3.2、WebSocket試圖將入棧消息解碼成開發人員使用的對象時 EncodeException類型。

3.3、WebSocket端點的其他方法運行時產生的錯誤,WebSocket實現將記錄端點操作過程中產生的任何異常 。

4、關閉事件:WebSocket鏈接端點關閉,做一些清理工作,可以由參與連接的任意一個端點發出。

(5) WebSocket關閉鏈接

1、伺服器關閉底層TCP鏈接

2、客戶端發起TCP Close

底層的TCP ,正常情況下應該首先由伺服器關閉 ,在異常情況下客戶端可以發起TCP Close。

流程:當伺服器被指示關閉WebSocket鏈接時,服務端會發起一個TCP Close操作, 客戶端應該等待伺服器的TCP Close。

5. WebSocket使用實例demo

(1)創建一個SpringBoot工程,工程結構如下

(2)啟動SpringBoot服務,訪問:localhost:8080/websocke

(3)啟動MainApp主程序,然後刷新頁面,就可以進行發送數據了。

效果圖如下:

由於篇幅問題,在此不再展示源碼,感興趣的朋友,代碼見github:

github.com/JavaCodeMood

分享就到這裡,感謝諸君的支持,如果對你有幫助,就點個贊吧!

作者:霜花似雪

鏈接:imooc.com/article/28974

來源:慕課網

本文首次發佈於慕課網 ,轉載請註明出處,謝謝合作

推薦閱讀:

相關文章