websocket 與Socket.IO介紹

一  websocket javascript

WebSocket是html5新增長的一種通訊協議,目前流行的瀏覽器都支持這個協議,例如 Chrome,Safrie,Firefox,Opera,IE等等,對該協議支持最先的應該是chrome,從chrome12就已經開始支持,隨着協 議草案的不斷變化,各個瀏覽器對協議的實現也在不停的更新。該協議仍是草案,沒有成爲標準,不過成爲標準應該只是時間問題了。html

1. WebSocket APIhtml5

首先看一段簡單的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();};程序員

ws.onclose = function(evt){console.log(「WebSocketClosed!」);};github

ws.onerror = function(evt){console.log(「WebSocketError!」);};web

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

第一行代碼是在申請一個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有更快的響應時間,獲得更好的用戶體驗。

 2 爲何引入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就是肩負這樣一個使命登上舞臺的。

3 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消息,而且能知道鏈接失敗的緣由。

4 websocket與TCP,HTTP的關係

 WebSocket與http協議同樣都是基於TCP的,因此他們都是可靠的協議,Web開發者調用的WebSocket的send函數在browser 的實現中最終都是經過TCP的系統接口進行傳輸的。WebSocket和Http協議同樣都屬於應用層的協議,那麼他們之間有沒有什麼關係呢?答案是確定 的,WebSocket在創建握手鍊接時,數據是經過http協議傳輸的,正如咱們上一節所看到的「GET/chat HTTP/1.1」,這裏面用到的只是http協議一些簡單的字段。可是在創建鏈接以後,真正的數據傳輸階段是不須要http協議參與的。

具體關係能夠參考下圖:

 

5 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

 值得一提的是:websocket是能夠和http共用監聽端口的,也就是它能夠公用端口完成socket任務。

二 Socket.io

node.js提供了高效的服務端運行環境,可是因爲瀏覽器端對HTML5的支持不一,爲了兼容全部瀏覽器,提供卓越的實時的用戶體驗,而且爲程序員提供客戶端與服務端一致的編程體驗,因而socket.io誕生。Socket.io將Websocket和輪詢 (Polling)機制以及其它的實時通訊方式封裝成了通用的接口,而且在服務端實現了這些實時機制的相應代碼。也就是說,Websocket僅僅是 Socket.io實現實時通訊的一個子集。那麼,Socket.io都實現了Polling中的那些通訊機制呢?

  • Adobe® Flash® Socket
  • AJAX long polling
  • AJAX multipart streaming
  • Forever Iframe
  • JSONP Polling

Adobe® Flash® Socket 大部分PC瀏覽器都支持的socket模式,不過是經過第三方嵌入到瀏覽器,不在W3C規範內,因此可能將逐步被淘汰,何況,大部分的手機瀏覽器都不支持這種模式。

AJAX long polling 這個很好理解,全部瀏覽器都支持這種方式,就是定時的向服務器發送請求,缺點是會給服務器帶來壓力而且出現信息更新不及時的現象。

AJAX multipart streaming  這是在XMLHttpRequest對象上使用某些瀏覽器(好比說Firefox)支持的multi-part標誌。Ajax請求被髮送給服務器端並保 持打開狀態(掛起狀態),每次須要向客戶端發送信息,就尋找一個掛起的的http請求響應給客戶端,而且全部的響應都會經過統一鏈接來寫入

複製代碼
var xhr = $.ajaxSettings.xhr(); xhr.multipart =true; xhr.open('GET', 'ajax', true); xhr.onreadystatechange = function() {   if (xhr.readyState == 4) {     processEvents($.parseJSON(xhr.responseText));   } }; xhr.send(null);
複製代碼

Forever Iframe (永存的Iframe)技術涉及了一個置於頁面中的隱藏Iframe標籤,該標籤的src屬性指向返回服務器端事件的servlet路徑。 每次在事件到達時,servlet寫入並刷新一個新的script標籤,該標籤內部帶有JavaScript代碼,iframe的內容被附加上這一 script標籤,標籤中的內容就會獲得執行。這種方式的缺點是接和數據都是由瀏覽器經過HTML標籤來處理的,所以你沒有辦法知道鏈接什麼時候在哪一端已被 斷開了,而且Iframe標籤在瀏覽器中將被逐步取消使用。

JSONP Polling  JSONP輪詢基本上與HTTP輪詢同樣,不一樣之處則是JSONP能夠發出跨域請求,詳細請搜索查詢jsonp的內容。

相關文章
相關標籤/搜索