天天看點

WebSocket協定開發

一直以來,網絡在很大程度上都是圍繞着HTTP的請求/響應模式而建構的。用戶端加載一個網頁,然後直到使用者點選下一頁之前,什麼都不會發生。在2005年左右,Ajax開始讓網絡變得更加動态了。但所有的HTTP通信仍然是由用戶端控制的,這就需要使用者進行互動或定期輪詢,以便從伺服器加載新資料。

長期以來存在着各種技術讓伺服器得知有新資料可用時,立即将資料發送到用戶端。這些技術種類繁多,例如“推送”或Comet。最常用的一種黑客手段是對伺服器發起連結建立假象,被稱為長輪詢。利用長輪詢,用戶端可以打開指向伺服器的HTTP連接配接,而伺服器會一直保持連接配接打開,直到發送響應。伺服器隻要實際擁有新資料,就會發送響應(其他技術包括Flash、XHR multipart請求和所謂的HTML Files)。長輪詢和其他技術都非常好用,在Gmail聊天等應用中會經常使用它們。

但是,這些解決方案都存在一個共同的問題:由于HTTP協定的開銷,導緻它們不适用于低延遲應用。

為了解決這些問題,WebSocket将網絡套接字引入到了用戶端和服務端,浏覽器和伺服器之間可以通過套接字建立持久的連接配接,雙方随時都可以互發資料給對方,而不是之前由用戶端控制的一請求一應答模式。

将HTTP協定的主要弊端總結如下。

(1)HTTP協定為半雙工協定。半雙工協定指資料可以在用戶端和服務端兩個方向上傳輸,但是不能同時傳輸。它意味着在同一時刻,隻有一個方向上的資料傳送;

(2)HTTP消息冗長而繁瑣。HTTP消息包含消息頭、消息體、換行符等,通常情況下采用文本方式傳輸,相比于其他的二進制通信協定,冗長而繁瑣;

(3)針對伺服器推送的黑客攻擊。例如長時間輪詢。

現在,很多網站為了實作消息推送,所用的技術都是輪詢。輪詢是在特定的的時間間隔(如每1秒),由浏覽器對伺服器發出HTTP request,然後由伺服器傳回最新的資料給用戶端浏覽器。這種傳統的模式具有很明顯的缺點,即浏覽器需要不斷地向伺服器送出請求,然而HTTP request的header是非常冗長的,裡面包含的可用資料比例可能非常低,這會占用很多的帶寬和伺服器資源。

比較新的一種輪詢技術是Comet,使用了Ajax。這種技術雖然可達到雙向通信,但依然需要送出請求,而且在Comet中,普遍采用了長連接配接,這也會大量消耗伺服器帶寬和資源。

為了解決HTTP協定效率低下的問題,HTML5定義了WebSocket協定,能更好地節省伺服器資源和帶寬并達到實時通信。

WebSocket是HTML5開始提供的一種浏覽器與伺服器間進行全雙工通信的網絡技術,WebSocket通信協定于2011年被IETF定為标準RFC6455,WebSocket API被W3C定為标準。

在WebSocket API中,浏覽器和伺服器隻需要做一個握手的動作,然後,浏覽器和伺服器之間就形成了一條快速通道,兩者就可以直接互相傳送資料了。WebSocket基于TCP雙向全雙工進行消息傳遞,在同一時刻,既可以發送消息,也可以接收消息,相比于HTTP的半雙工協定,性能得到很大提升。

下面總結一下WebSocket的特點。

單一的TCP連接配接,采用全雙工模式通信;

對代理、防火牆和路由器透明;

無頭部資訊、Cookie和身份驗證;

無安全開銷;

通過“ping/pong”幀保持鍊路激活;

伺服器可以主動傳遞消息給用戶端,不再需要用戶端輪詢。

建立WebSocket連接配接時,需要通過用戶端或者浏覽器發出握手請求,請求消息示例如圖:

WebSocket協定開發

服務端傳回給用戶端的應答消息如圖:

WebSocket協定開發

為了建立一個WebSocket連接配接,用戶端浏覽器首先要向伺服器發起一個HTTP請求,這個請求和通常的HTTP請求不同,包含了一些附加頭資訊,其中附加頭資訊“Upgrade: WebSocket”表明這是一個申請協定更新的HTTP請求。伺服器端解析這些附加的頭資訊,然後生成應答資訊傳回給用戶端,用戶端和伺服器端的WebSocket連接配接就建立起來了,雙方可以通過這個連接配接通道自由地傳遞資訊,并且這個連接配接會持續存在直到用戶端或者伺服器端的某一方主動關閉連接配接。

請求消息中的“Sec-WebSocket-Key”是随機的,伺服器端會用這些資料來構造出一個SHA-1的資訊摘要,把“Sec-WebSocket-Key”加上一個魔幻字元串“258EAFA5-E914- 47DA-95CA-C5AB0DC85B11”。使用SHA-1加密,然後進行BASE-64編碼,将結果做為“Sec-WebSocket-Accept”頭的值,傳回給用戶端。

握手成功之後,服務端和用戶端就可以通過“messages”的方式進行通信了,一個消息由一個或者多個幀組成,WebSocket的消息并不一定對應一個特定網絡層的幀,它可以被分割成多個幀或者被合并。

幀都有自己對應的類型,屬于同一個消息的多個幀具有相同類型的資料。從廣義上講,資料類型可以是文本資料(UTF-8[RFC3629]文字)、二進制資料和控制幀(協定級信令,如信号)。

WebSocket連接配接生命周期示意圖如圖:

WebSocket協定開發

為關閉WebSocket連接配接,用戶端和服務端需要通過一個安全的方法關閉底層TCP連接配接以及TLS會話。如果合适,丢棄任何可能已經接收的位元組;必要時(比如受到攻擊),可以通過任何可用的手段關閉連接配接。

底層的TCP連接配接,在正常情況下,應該首先由伺服器關閉。在異常情況下(例如在一個合理的時間周期後沒有接收到伺服器的TCP Close),用戶端可以發起TCP Close。是以,當伺服器被訓示關閉WebSocket連接配接時,它應該立即發起一個TCP Close操作;用戶端應該等待伺服器的TCP Close。

WebSocket的握手關閉消息帶有一個狀态碼和一個可選的關閉原因,它必須按照協定要求發送一個Close控制幀,當對端接收到關閉控制幀指令時,需要主動關閉WebSocket連接配接。

Netty基于HTTP協定棧開發了WebSocket協定棧,利用Netty的WebSocket協定棧可以非常友善地開發出WebSocket用戶端和服務端。

WebSocket服務端的功能如下:支援WebSocket的浏覽器通過WebSocket協定發送請求消息給服務端,服務端對請求消息進行判斷,如果是合法的WebSocket請求,則擷取請求消息體(文本),并在後面追加字元串“歡迎使用Netty WebSocket服務,現在時刻:系統時間”。

用戶端HTML通過内嵌的JS腳本建立WebSocket連接配接,如果握手成功,在文本框中列印“打開WebSocket服務正常,浏覽器支援WebSocket!”。

首先對WebSocket服務端的功能進行簡單地講解。WebSocket服務端接收到請求消息之後,先對消息的類型進行判斷,如果不是WebSocket握手請求消息,則傳回 HTTP 400 BAD REQUEST 響應給用戶端。

WebSocket協定開發

服務端對握手請求消息進行處理,構造握手響應傳回,雙方的Socket連接配接正式建立,服務端傳回的握手應答消息:

WebSocket協定開發

連接配接建立成功後,到被關閉之前,雙方都可以主動向對方發送消息,這點跟HTTP的一請求一應答模式存在很大的差别。相比于HTTP,它的網絡使用率更高,可以通過全雙工的方式進行消息發送和接收。

html代碼示例:

上一篇: UDP協定開發

繼續閱讀