概述
TheWebSocketProtocolenablestwo-waycommunicationbetweenaclientrunninguntrustedcodeinacontrolledenvironmenttoaremotehostthathasopted-intocommunicationsfromthatcode.Thesecuritymodelusedforthisistheorigin-basedsecuritymodelcommonlyusedbywebbrowsers.Theprotocolconsistsofanopeninghandshakefollowedbybasicmessageframing,layeredoverTCP.Thegoalofthistechnologyistoprovideamechanismforbrowser-basedapplicationsthatneedtwo-waycommunicationwithserversthatdoesnotrelyonopeningmultipleHTTPconnections(e.g.,usingXMLHttpRequestor<iframe>sandlongpolling).
WebSocket協定支持(在受控環境中運行不受信任的代碼的)客戶端與(選擇加入該代碼的通信的)遠程主機之間進行全雙工通信。用於此的安全模型是Web瀏覽器常用的基於原始的安全模式。協定包括一個開放的握手以及隨後的TCP層上的訊息幀。該技術的目標是為基於瀏覽器的、需要和伺服器進行雙向通信的(伺服器不能依賴於打開多個HTTP連線(例如,使用XMLHttpRequest或<iframe>和長輪詢))應用程式提供一種通信機制。
背景
簡單的說,WebSocket協定之前,雙工通信是通過不停傳送HTTP請求,從伺服器拉取更新來實現,這導致了效率低下。WebSocket解決了這個問題。下面是標準RFC6455中的產生背景概述。
Historically,creatingwebapplicationsthatneedbidirectionalcommunicationbetweenaclientandaserver(e.g.,instantmessagingandgamingapplications)hasrequiredanabuseofHTTPtopulltheserverforupdateswhilesendingupstreamnotificationsasdistinctHTTPcalls.
Thisresultsinavarietyofproblems:
oTheserverisforcedtouseanumberofdifferentunderlyingTCPconnectionsforeachclient:oneforsendinginformationtotheclientandanewoneforeachincomingmessage.
oThewireprotocolhasahighoverhead,witheachclient-to-servermessagehavinganHTTPheader.oTheclient-sidescriptisforcedtomaintainamappingfromtheoutgoingconnectionstotheincomingconnectiontotrackreplies.
AsimplersolutionwouldbetouseasingleTCPconnectionfortrafficinbothdirections.ThisiswhattheWebSocketProtocolprovides.CombinedwiththeWebSocketAPI,itprovidesanalternativetoHTTPpollingfortwo-waycommunicationfromawebpagetoaremoteserver.
TheWebSocketProtocolisdesignedtosupersedeexistingbidirectionalcommunicationtechnologiesthatuseHTTPasatransportlayer.Suchtechnologieswereimplementedastrade-offsbetweenefficiencyandreliabilitybecauseHTTPwasnotinitiallymeanttobeusedforbidirectionalcommunication(see[RFC6202]forfurtherdiscussion).[1]
長久以來,創建實現客戶端和用戶端之間雙工通訊的webapp都會造成HTTP輪詢的濫用:客戶端向主機不斷發送不同的HTTP呼叫來進行詢問。
這會導致一系列的問題:
1.伺服器被迫為每個客戶端使用許多不同的底層TCP連線:一個用於向客戶端傳送信息,其它用於接收每個傳入訊息。
2.有些協定有很高的開銷,每一個客戶端和伺服器之間都有HTTP頭。
3.客戶端腳本被迫維護從傳出連線到傳入連線的映射來追蹤回復。
一個更簡單的解決方案是使用單個TCP連線雙向通信。這就是WebSocket協定所提供的功能。結合WebSocketAPI,WebSocket協定提供了一個用來替代HTTP輪詢實現網頁到遠程主機的雙向通信的方法。
WebSocket協定被設計來取代用HTTP作為傳輸層的雙向通訊技術,這些技術只能犧牲效率和可依賴性其中一方來提高另一方,因為HTTP最初的目的不是為了雙向通訊。(獲得更多關於此的討論可查閱RFC6202)
原理
WebSocket protocol 是HTML5一種新的協定(protocol)。它是實現了瀏覽器與伺服器全雙工通信(full-duplex)。
現很多網站為了實現即時通訊(real-time),所用的技術都是輪詢(polling)。輪詢是在特定的的時間間隔(time interval)(如每1秒),由瀏覽器對伺服器發出HTTP request,然後由伺服器返回最新的數據給客服端的瀏覽器。這種傳統的HTTP request 的模式帶來很明顯的缺點 – 瀏覽器需要不斷的向伺服器發出請求(request),然而HTTP request 的header是非常長的,裡面包含的數據可能只是一個很小的值,這樣會占用很多的頻寬。
而最比較新的技術去做輪詢的效果是Comet – 用了AJAX。但這種技術雖然可達到全雙工通信,但依然需要發出請求(reuqest)。
在 WebSocket API,瀏覽器和伺服器只需要要做一個握手的動作,然後,瀏覽器和伺服器之間就形成了一條快速通道。兩者之間就直接可以數據互相傳送。在此WebSocket 協定中,為我們實現即時服務帶來了兩大好處:
1. Header
互相溝通的Header是很小的-大概只有 2 Bytes
2. Server Push
伺服器可以主動傳送數據給客戶端
握手協定
在實現websocket連線過程中,需要通過瀏覽器發出websocket連線請求,然後伺服器發出回應,這個過程通常稱為“握手” (handshaking)。
PS1:握手協定在後期的版本中,會標明版本編號,下面的例子屬於早期的協定之一,對於新版的 chrome 和 Firefox 皆不適用。
PS2:後期的版本大多屬於功能上的擴充,例如使用第7版的握手協定同樣也適用於第8版的握手協定。
例子:
瀏覽器請求
GET /demo HTTP/1.1Host: 你的網址.com
Connection: Upgrade
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Upgrade: WebSocket
Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
Origin: http://你的網址.com
^n:ds[4U
//2010年之後的新版本websocket協定的Sec-WebSocket-Key只有一個,新的瀏覽只支持一個的,google的phpwebsocket用的是之前的協定所以不能直接運行通過,現在有個新版本是基於這個協定的是php-websocket-server-1
伺服器回應
HTTP/1.1 101
WebSocket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Origin: http://你的網址.com
Sec-WebSocket-Location: ws://你的網址.com/demo
Sec-WebSocket-Protocol: sample
8jKS’y:G*Co,Wxa-
伺服器返回
Upgrade:websocket
Connection:Upgrade
告訴瀏覽器即將升級的是Websocket協定
Sec-WebSocket-Accept是將請求包“Sec-WebSocket-Key”的值,與”258EAFA5-E914-47DA-95CA-C5AB0DC85B11″這個字元串進行拼接,然後對拼接後的字元串進行sha-1運算,再進行base64編碼得到的。用來說明自己是WebSocket助理伺服器。
Sec-WebSocket-Version是WebSocket協定版本號。RFC6455要求使用的版本是13,之前草案的版本均應當被棄用。
更多握手規範詳見RFC6455。
HTML5
在HTML5中內置有一些API,用於回響應用程式發起的請求。基本API語句如下:
創建對象
varws=newWebSocket(url,name);
url為WebSocket伺服器的地址,name為發起握手的協定名稱,為可選擇項。
傳送文本訊息
ws.send(msg);
msg為文本訊息,對於其他類型的可以通過二進制形式傳送。
接收訊息
ws.onmessage=(function(){...})();
錯誤處理
ws.onerror=(function(){...})();
關閉連線
ws.close();
語言支持
所有主流瀏覽器都支持RFC6455。但是具體的WebSocket版本有區別。phpjettynettyrubyKaazingnginxpythonTomcatDjangoerlang netty.net等語言均可以用來實現支持WebSocket的伺服器。
websocketapi在瀏覽器端的廣泛實現似乎只是一個時間問題了,值得注意的是伺服器端沒有標準的api,各個實現都有自己的一套api,並且tcp也沒有類似的提案,所以使用websocket開發伺服器端有一定的風險.可能會被鎖定在某個平台上或者將來被迫升級。