WebSocket協議


websocket 簡介

  (2013-04-09 15:39:28)
  分類: websocket

一 

 

WebSocket是html5新增加的一種通信協議,目前流行的瀏覽器都支持這個協議,例如Chrome,Safrie,Firefox,Opera,IE等等,對該協議支持最早的應該是chrome,從chrome12就已經開始支持,隨着協議草案的不斷變化,各個瀏覽器對協議的實現也在不停的更新。該協議還是草案,沒有成為標准,不過成為標准應該只是時間問題了,從WebSocket草案的提出到現在已經有十幾個版本了,目前最新的是版本17,所對應的協議版本號為13,目前對該協議支持最完善的瀏覽器應該是chrome,畢竟WebSocket協議草案也是Google發布的。

1.     WebSocket API簡介

首先看一段簡單的javascript代碼,該代碼調用了WebSockets的API。

var ws = new WebSocket(“ws://echo.websocket.org”);

ws.onopen = function(){ws.send(“Test!”); };

ws.onmessage = function(evt){console.log(evt.data);ws.close();};

ws.onclose = function(evt){console.log(“WebSocketClosed!”);};

ws.onerror = function(evt){console.log(“WebSocketError!”);};

這份代碼總共只有5行,現在簡單概述一下這5行代碼的意義。

第一行代碼是在申請一個WebSocket對象,參數是需要連接的服務器端的地址,同http協議使用http://開頭一樣,WebSocket協議的URL使用ws://開頭,另外安全的WebSocket協議使用wss://開頭。

第二行到第五行為WebSocket對象注冊消息的處理函數,WebSocket對象一共支持四個消息 onopen, onmessage, onclose和onerror,當Browser和WebSocketServer連接成功后,會觸發onopen消息;如果連接失敗,發送、接收數據失敗或者處理數據出現錯誤,browser會觸發onerror消息;當Browser接收到WebSocketServer發送過來的數據時,就會觸發onmessage消息,參數evt中包含server傳輸過來的數據;當Browser接收到WebSocketServer端發送的關閉連接請求時,就會觸發onclose消息。我們可以看出所有的操作都是采用消息的方式觸發的,這樣就不會阻塞UI,使得UI有更快的響應時間,得到更好的用戶體驗。

 

為什么引入WebSocket協議??

Browser已經支持http協議,為什么還要開發一種新的WebSocket協議呢?我們知道http協議是一種單向的網絡協議,在建立連接后,它只允許Browser/UA(UserAgent)向WebServer發出請求資源后,WebServer才能返回相應的數據。而WebServer不能主動的推送數據給Browser/UA,當初這么設計http協議也是有原因的,假設WebServer能主動的推送數據給Browser/UA,那Browser/UA就太容易受到攻擊,一些廣告商也會主動的把一些廣告信息在不經意間強行的傳輸給客戶端,這不能不說是一個災難。那么單向的http協議給現在的網站或Web應用程序開發帶來了哪些問題呢?

讓我們來看一個案例,現在假設我們想開發一個基於Web的應用程序去獲取當前Web服務器的實時數據,例如股票的實時行情,火車票的剩余票數等等,這就需要Browser/UA與WebServer端之間反復的進行http通信,Browser不斷的發送Get請求,去獲取當前的實時數據。下面介紹幾種常見的方式:

1.     Polling

這種方式就是通過Browser/UA定時的向Web服務器發送http的Get請求,服務器收到請求后,就把最新的數據發回給客戶端(Browser/UA),Browser/UA得到數據后,就將其顯示出來,然后再定期的重復這一過程。雖然這樣可以滿足需求,但是也仍然存在一些問題,例如在某段時間內Web服務器端沒有更新的數據,但是Browser/UA仍然需要定時的發送Get請求過來詢問,那么Web服務器就把以前的老數據再傳送過來,Browser/UA把這些沒有變化的數據再顯示出來,這樣顯然既浪費了網絡帶寬,又浪費了CPU的利用率。如果說把Browser發送Get請求的周期調大一些,就可以緩解這一問題,但是如果在Web服務器端的數據更新很快時,這樣又不能保證Web應用程序獲取數據的實時性。

2.     Long Polling

上面介紹了Polling遇到的問題,現在介紹一下LongPolling,它是對Polling的一種改進。

Browser/UA發送Get請求到Web服務器,這時Web服務器可以做兩件事情,第一,如果服務器端有新的數據需要傳送,就立即把數據發回給Browser/UA,Browser/UA收到數據后,立即再發送Get請求給Web Server;第二,如果服務器端沒有新的數據需要發送,這里與Polling方法不同的是,服務器不是立即發送回應給Browser/UA,而是把這個請求保持住,等待有新的數據到來時,再來響應這個請求;當然了,如果服務器的數據長期沒有更新,一段時間后,這個Get請求就會超時,Browser/UA收到超時消息后,再立即發送一個新的Get請求給服務器。然后依次循環這個過程。

這種方式雖然在某種程度上減小了網絡帶寬和CPU利用率等問題,但是仍然存在缺陷,例如假設服務器端的數據更新速率較快,服務器在傳送一個數據包給Browser后必須等待Browser的下一個Get請求到來,才能傳遞第二個更新的數據包給Browser,那么這樣的話,Browser顯示實時數據最快的時間為2×RTT(往返時間),另外在網絡擁塞的情況下,這個應該是不能讓用戶接受的。另外,由於http數據包的頭部數據量往往很大(通常有400多個字節),但是真正被服務器需要的數據卻很少(有時只有10個字節左右),這樣的數據包在網絡上周期性的傳輸,難免對網絡帶寬是一種浪費。

通過上面的分析可知,要是在Browser能有一種新的網絡協議,能支持客戶端和服務器端的雙向通信,而且協議的頭部又不那么龐大就好了。WebSocket就是肩負這樣一個使命登上舞台的。

 

三 websocket協議簡介

 

WebSocket協議是一種雙向通信協議,它建立在TCP之上,同http一樣通過TCP來傳輸數據,但是它和http最大的不同有兩點:1.WebSocket是一種雙向通信協議,在建立連接后,WebSocket服務器和Browser/UA都能主動的向對方發送或接收數據,就像Socket一樣,不同的是WebSocket是一種建立在Web基礎上的一種簡單模擬Socket的協議;2.WebSocket需要通過握手連接,類似於TCP它也需要客戶端和服務器端進行握手連接,連接成功后才能相互通信。

下面是一個簡單的建立握手的時序圖:

這里簡單說明一下WebSocket握手的過程。

當Web應用程序調用new WebSocket(url)接口時,Browser就開始了與地址為url的WebServer建立握手連接的過程。

1.     Browser與WebSocket服務器通過TCP三次握手建立連接,如果這個建立連接失敗,那么后面的過程就不會執行,Web應用程序將收到錯誤消息通知。

2.     在TCP建立連接成功后,Browser/UA通過http協議傳送WebSocket支持的版本號,協議的字版本號,原始地址,主機地址等等一些列字段給服務器端。

例如:

GET /chat HTTP/1.1

Host: server.example.com

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Key:dGhlIHNhbXBsZSBub25jZQ==

Origin: http://example.com

Sec-WebSocket-Protocol: chat,superchat

Sec-WebSocket-Version: 13

3.     WebSocket服務器收到Browser/UA發送來的握手請求后,如果數據包數據和格式正確,客戶端和服務器端的協議版本號匹配等等,就接受本次握手連接,並給出相應的數據回復,同樣回復的數據包也是采用http協議傳輸。

HTTP/1.1 101 Switching Protocols

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Accept:s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

Sec-WebSocket-Protocol: chat

4.     Browser收到服務器回復的數據包后,如果數據包內容、格式都沒有問題的話,就表示本次連接成功,觸發onopen消息,此時Web開發者就可以在此時通過send接口想服務器發送數據。否則,握手連接失敗,Web應用程序會收到onerror消息,並且能知道連接失敗的原因。

四 websocket與TCP,HTTP的關系。

 

WebSocket與http協議一樣都是基於TCP的,所以他們都是可靠的協議,Web開發者調用的WebSocket的send函數在browser的實現中最終都是通過TCP的系統接口進行傳輸的。WebSocket和Http協議一樣都屬於應用層的協議,那么他們之間有沒有什么關系呢?答案是肯定的,WebSocket在建立握手連接時,數據是通過http協議傳輸的,正如我們上一節所看到的“GET/chat HTTP/1.1”,這里面用到的只是http協議一些簡單的字段。但是在建立連接之后,真正的數據傳輸階段是不需要http協議參與的。

具體關系可以參考下圖:

 

 

五websocket server

 

果要搭建一個Web服務器,我們會有很多選擇,市場上也有很多成熟的產品供我們應用,比如開源的Apache,安裝后只需簡單的配置(或者默認配置)就可以工作了。但是如果想搭建一個WebSocket服務器就沒有那么輕松了,因為WebSocket是一種新的通信協議,目前還是草案,沒有成為標准,市場上也沒有成熟的WebSocket服務器或者Library實現WebSocket協議,我們就必須自己動手寫代碼去解析和組裝WebSocket的數據包。要這樣完成一個WebSocket服務器,估計所有的人都想放棄,幸好的是市場上有幾款比較好的開源庫供我們使用,比如PyWebSocket,WebSocket-Node, LibWebSockets等等,這些庫文件已經實現了WebSocket數據包的封裝和解析,我們可以調用這些接口,這在很大程度上減少了我們的工作量。

下面就簡單介紹一下這些開源的庫文件。

1.     PyWebSocket

PyWebSocket采用Python語言編寫,可以很好的跨平台,擴展起來也比較簡單,目前WebKit采用它搭建WebSocket服務器來做LayoutTest。

我們可以獲取源碼通過下面的命令

svn checkouthttp://pywebsocket.googlecode.com/svn/trunk/ pywebsocket-read-only

更多的詳細信息可以從http://code.google.com/p/pywebsocket/獲取。

2.     WebSocket-Node

WebSocket-Node采用JavaScript語言編寫,這個庫是建立在nodejs之上的,對於熟悉JavaScript的朋友可參考一下,另外Html5和Web應用程序受歡迎的程度越來越高,nodejs也正受到廣泛的關注。

我們可以從下面的連接中獲取源碼

https://github.com/Worlize/Websocket-Node

3.     LibWebSockets

LibWebSockets采用C/C++語言編寫,可定制化的力度更大,從TCP監聽開始到封包的完成我們都可以參與編程。

我們可以從下面的命令獲取源代碼

git clone git://git.warmcat.com/libwebsockets


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM