Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Netty in Action (二十三) 第十二章節 WebSocket

Netty in Action (二十三) 第十二章節 WebSocket

編輯:關於Android編程

第三部分:網絡協議

 

WebSocket是一個先進的網絡協議,被開發用來用來提高網絡的性能和web應用的響應率,我們將介紹Netty對WebSocket這兩個特性的支持,同時我們也會舉一個簡單的實例來說明講解這兩個WebSocket的特性

 

在第十二章節中,你將學會如何使用WebSocket實現數據雙向傳輸的功能,我們會寫一個聊天室的方式講解這個數據雙向傳輸的問題,我們這個聊天室的實例是這樣的:多個浏覽器客戶端可是實時的相互通信,你也會學會如何將普通的HTTP協議切換升級成WebSocket協議,當然我們需要提前檢測客戶端是否支持WebSocket

 

我們也會在第三部分的最後介紹Netty對User Dategram Protocol(UDP)協議的支持,我們將會構建一個廣播機制的服務器,並且會監控客戶端的狀態,以致客戶端可以適用更多的實際的使用

 

 

第十二章:WebSocket

本章內容包括:

1)實時網絡的概念

2)WebSocket協議

3)使用Netty構建基於WebSocket的聊天室服務端

 

如果你比較了解近期的Web應用的發展的話,你肯定會接觸過“實時web”這個概念,如果你有實時系統有過實戰的經驗的話,你可能會在質疑“實時web”這個意味著什麼

 

所以我們一開始就需要澄清這個概念,這並不是我們稱之為“全實時品質服務”,我們可以稱之為“近實時服務”,在這種場景下,後台的計算結果必須在指定的時間內給以傳播,這個指定的時間比較給以保證,但是請求響應的這種HTTP協議設計並不是適合這種場景,如果運用到這種場景會有很多問題,因為你不知道什麼時候去請求,截止到目前為止,事實證明目前還沒有任何方案被設計出來,還沒有任何方案被認為是令人滿意的

 

盡管現在還有很多學術的討論關於“timed web services”這個詞匯的定義,現在被普遍接受的概念目前為止還沒有出現,所以目前為止,我們只能從維基百科中接受一個並不是權威的對real-time web的定義:

一個近實時的web是需要網絡web系統使用某種技術或者某種策略使使用者能夠最快速度的獲取信息,而不是需要使用者或者客戶端使用他們的軟件去主動調用或者檢測某個數據源是否發生了變更

 

從技術上簡單地陳述一下,也許一個成熟的實時web也許還沒有真正的到來,但是在這個理念會加速大家對這個技術的期望,有了這種技術你可以幾乎瞬發地獲取到信息,這個章節我們討論的WebSocket協議是近實時技術研究方向上前進的很扎實的一步

 

12.1 Introducing WebSocket

 

WebSocket協議是被設計來用來解決web應用中數據雙向傳輸的一個實際的解決方案,這種協議可以是服務器和客戶端在任何事件可以傳輸信息,因此,需要它們可以異步地處理信息

 

Netty對WebSocket的支持包括了對WebSocket的很多主要實現,所以你可以直接在你的項目中直接采用Netty提供的WebSocket服務是很直接方便的,與Netty設計的理念一樣,你可以充分地使用WebSocket協議在不需要關心它內部的實現細節上,我們將通過使用WebSocket協議創建一個實時的web版的聊天系統

 

12.2 Our example WebSocket application

 

我們的示例應用將通過使用WebSocket協議來實現一個基於浏覽器的聊天應用來說明實時通訊的功能,這種實例很類似於你在FaceBook上遇到的那種文本消息的交互,我們也會將我們的示例支持多個用戶可以同時使用,進行相互通信

 

圖12.1說明了我們示例的主要邏輯

1)客戶端發送信息

2)發送的信息廣播到所有其他鏈接的客戶端中

 

這就是一個聊天室如何工作的基本邏輯:每個人可以其他的每個人進行交談,在我們的示例中我們只會實現我們的服務端的代碼,客戶端則是通過浏覽器的一些功能去簡單實現的,在接下來的幾頁內容裡,你會看見Netty的WebSocket是如何簡單地構建這個示例的

\

12.3 Adding WebSocket support

 

升級握手機制被用來將標准的HTTP協議或者HTTPS協議切換成WebSocket協議,當然一個應用會以HTTP/S開始在需要升級的場景下升級為WebSocket應用,這種升級可以是由某個具體的URL指定觸發的

 

我們的應用就會使用這樣的升級機制,如果一個URL請求是以/ws為結尾的,我們將協議升級成WebSocket協議,否則我們默認使用最基本的HTTP/S協議,當連接成功升級之後,所有的數據將使用WebSocket協議進行傳播,圖12.2說明了服務器的邏輯,服務器使用的是Netty,具體是通過一系列的ChannelHandler實現的,在下一個小節中,我們將具體來描述這些組件,我們會解釋這些處理HTTP和WebSocket協議的技術

 

12.3.1 Handling HTTP requests

 

首先我們將會實現用來處理HTTP請求的組件,這個組件服務於網頁端,用來提供聊天室的入口,並且用來展示由每個連接客戶端發送信息的展示,代碼清單12.1展示了HttpRequestHandler的具體實現,這個類繼承於SimpleChannelInboundHandler用來處理FullHttpRequest信息,請注意代碼實現中,方法channelRead0的實現是如何處理URI中以/ws為結尾的請求的

\

\

\

\

如果一個URI請求中有“/ws”的時候,HttpRequestHandler將會在FullHttpRequest上調用retain方法,再通過fireChannelRead(msg)方法使其轉向到下一個ChannelInboundHandler中,調用retain是有必要的,因為在channelRead方法完成之後,它將會對FullHttpRequest調用release方法來釋放資源

 

如果一個客戶端發送一個HTTP1.1的消息頭,期待一個"100-continue",那麼HttpRequestHandler將會發送一個100-continue的響應,在所有的消息頭被設置後,HttpRequestHandler將會寫一個HttpResponse返回給客戶端,返回的並不是一個完整的FullHttpResponse,因為它只是響應的第一個部分,所以在這裡並沒有調用writeAndFlush方法,這個方法將會在結尾調用

 

 

如果加密和壓縮都不需要的情況下,那麼我們可以在DefaultFileRegion中存儲index.html的內容,這樣可以獲取最大的效率,這樣可以利用零拷貝技術來獲取最高的傳輸效率,因為這個理由,你可以了解在一個ChannelPipeline中是否有SslHandler,如果有,你就有可選方案可以使用ChunkedNioFile

 

HttpRequestHandler寫一個LastHttpContent來標記一個響應的結束,如果不需要keepalive,那麼HttpRequestHandler將會在最後寫入結束的時候的ChannelFuture增加一個ChannelFutureListener來關閉連接,在這裡你就可以調用writeAndFlush方法來將值錢所有寫入的信息刷入

 

目前為止,這塊代碼代表了聊天室的第一個模塊,它將管理純淨的HTTP請求和響應,下一個小節,我們將處理WebSocket協議的幀數據,這個數據將承載著真實的聊天信息

 

12.3.2 Handling WebSocket frames

 

RFC的WebSocket協議由IETF發布的,規范了六種類型的幀數據,Netty為每一種幀數據提供了一個POJO的實現,表12.1列出了這些幀數據的類型並且描述他們的使用說明

 

\

我們的聊天室將使用如下的數據幀類型

1)CloseWebSocketFrame

2)PingWebSocketFrame

3)PongWebSocketFrame

4)TextWebSocketFrame

 

事實上TextWebSocketFrame類型的數據是我們真正需要處理的,為了符合RFC的WebSocket,Netty提供了WebSocketServerProtocolHandler來管理其他類型的幀數據

 

 

下面的代碼清單展示用來處理TextWebSocketFrame的ChannelInboundHandler,這個也可以用來追蹤在ChannelGroup中的存活的WebSocket連接

 

\

TextWebSocketFrameHandler只負責很小一塊的功能,當WebSocket與新的客戶端成功握手之後,它將會通知所有的連接著的所有客戶端,通過將其寫入ChannelGroup的所有Channel中,然後它將新增的Channel寫入ChannelGroup中

 

如果一個TextWebSocketFrame被接收,那麼它將對TextWebSocketFrame對象調用retain方法,然後使用writeAndFlush方法將其傳輸到ChannelGroup中以致於所有的連接的WebSocket的Channel都能接收到這個訊息

 

在之前,調用retain方法是有必要的,是因為當channelRead0的方法返回的時候TextWebSocketFrame這個對象的計數引用會遞減一,因為所有的操作都是異步的,writeAndFlush可能會在有一定的延遲的時間內完成,所以我們不允許獲取一個不合法的對象引用,所以調用retain方法

 

因為Netty內部已經給我們的WebSocket的實現完成了大部分的工作,唯一剩下來的事情就是初始化好ChannelPipeline,因為每一個新的Channel都在這創建的,因為這個原因,我們需要一個ChannelInitializer

 

12.3.3 Initializing the ChannelPipeline

 

因為我們之前已經學習過,在ChannelPipeline中安裝ChannelHandler時,你只需要繼承ChannelInitializer類,然後實現initChannel方法,下面的代碼清單展示了ChatServerInitializer的具體實際代碼
\

initChannel方法的調用可以設置ChannelPipeline中注冊的Channel,通過這種方法可以安裝所需的所有ChannelHandler,在表12.2給出了部分摘要,每一個都描述了他們自己負責的功能

 

\

 

\

Netty的WebSocketServerProtocolHandler處理所有已經授權的WebSocket幀類型的數據,並且同時升級握手,如果握手成功,指定的一些ChannelHandler需要增加到管道中,如果沒有需要,那麼這些handler將不會再從管道中移除

 

\

 

在協議升級之前管道的狀態如圖12.3所示,這張圖代表了又ChatServerInitializer初始化之後的管道的狀態

 

當協議升級之後,WebSocketServerProtocolHandler將會以WebSocketFrameDecoder取代HttpRequestDecoder,以WebSocketFrameEncoder取代HttpResponseEncoder
,為了最大化性能,它會在這個時候移除任何不需要的多余的Handler,這些Handler可能WebSocket使用不到,這些Handler包括如12.3所示的HttpObjectAggregator和HttpRequestHandler

\

圖12.4展示了當操作升級完成後管道的狀態,注意目前為止Netty支持四種類型版本的WebSocket,每一個版本都有他們自己的實現,選擇正確的WebSocketFrameDecoder和WebSocketFrameEncoder這個行為是自動完成的,這取決於你客戶端也就是浏覽器支持哪一種版本的webSocket

 


12.3.4 Bootstrapping

這個聊天室的最後一個模塊就是啟動服務器初始化所有的ChatServerInitializer,這些動作將被ChatServer處理,如下面展示的一樣

\

\

應用的所有代碼已經完成了,現在我們開始測試

12.4 Testing the application

 

第十二章節的所有代碼示例已經全部給出了,現在你需要構建運行測試用例,我們可以使用如下的Maven命令來構建和啟動項目

\

 

這個項目的pom.xml配置了在端口9999來啟動項目,如果你想要使用其他的端口,你可以不需要編輯改變量,你可以在命令中重新覆蓋該變量

\

下面是控制台打印的構建和啟動的日記

\

 

\

在你的浏覽器中輸入http://localhost:9999來進入你的應用,圖12.5展示了Chrome浏覽器的UI

 

圖12.5展示了兩個鏈接的客戶端,第一個連接是使用浏覽器頁面頭部提供的輸入接口,第二個連接是通過浏覽器的底部的控制台連接的,你會發現無論從這兩個客戶端的發送的信息,發送的信息都能夠在其他的客戶端中正常的展示

 

這就是一個完整的示例,這個示例很好地展示了在一個浏覽器中WebSocket如何構建一個實時通訊的

 

12.4.1 What about encryption?

 

在真實的生產環境中,你將很快被要求將加密器加入到你的應用中,對於Netty應用來說,這是小事一樁,你只需要將SslHandler加入到ChannelPipeline中去然後配置一下就可以了,下面的代碼清單展示了我們是如何實現這個功能的,我們只需要創建一個SecureChatServerInitializer,使其繼承與ChatServerInitializer就可以了

 

 

\

\

最後一步就是讓ChatServer采用我們剛剛創建的SecureChatServerInitializer這樣就可以使SslHandler加入到管道中去,我們使用SecureChatServer實現了這個效果

\

這樣就可以使整個通訊都支持SSL/TLS的加密了,與之前一樣,我們依舊使用Maven去構建一下

\

現在你又可以在http://localhost:9999看到SecureChatServer了

 

12.5 Summary

在這個章節中,我們使用了Netty實現的WebSocket寫了一個網頁版的實時數據系統,我們講解了WebSocket支持的數據類型,也討論了我們遇到的一些限制,盡管並不是每一個場景都可以使用WebSocket的,但是有一點是毫無疑問的,對於web開發來說,WebSocket技術是這個方面的一個很重要的一大突破

 

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved