分類: websocket |
一 javascript
WebSocket是html5新增長的一種通訊協議,目前流行的瀏覽器都支持這個協議,例如Chrome,Safrie,Firefox,Opera,IE等等,對該協議支持最先的應該是chrome,從chrome12就已經開始支持,隨着協議草案的不斷變化,各個瀏覽器對協議的實現也在不停的更新。該協議仍是草案,沒有成爲標準,不過成爲標準應該只是時間問題了,從WebSocket草案的提出到如今已經有十幾個版本了,目前最新的是版本17,所對應的協議版本號爲13,目前對該協議支持最完善的瀏覽器應該是chrome,畢竟WebSocket協議草案也是Google發佈的。html
1. WebSocket API簡介html5
首先看一段簡單的javascript代碼,該代碼調用了WebSockets的API。java
var ws = new WebSocket(「ws://echo.websocket.org」);node
ws.onopen = function(){ws.send(「Test!」); };git
ws.onmessage = function(evt){console.log(evt.data);ws.close();};github
ws.onclose = function(evt){console.log(「WebSocketClosed!」);};web
ws.onerror = function(evt){console.log(「WebSocketError!」);};chrome
這份代碼總共只有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