WebSocket實戰

前言html

  互聯網發展到如今,早已超越了原始的初衷,人類歷來沒有像如今這樣依賴過他;也正是這種依賴,促進了互聯網技術的飛速發展。而終端設備的創新與發展,更加速了互聯網的進化;前端

HTTP/1.1規範發佈於1999年,同年12月24日,HTML4.01規範發佈;儘管已到2012年,但HTML4.01還是主流;雖然 HTML5的草案已出現了好幾個年頭,但轉正日期,遙遙無期,少則三五年,多則數十年;而HTML5的客戶代理(對於通常用戶而言,就是瀏覽器),則已百 家爭鳴,星星向榮;再加上移動終端的飛速發展,在大多數狀況下,咱們均可以保證擁有一個HTML5的運行環境,因此,咱們來分享一下HTML5中的 WebSocket協議;android

本文包含如下六個方面:web

1. WebSocket的前世此生sql

2. WebSocket是什麼chrome

3. 爲何使用WebSocketnpm

4. 搭建WebSocket服務器編程

5. WebSocket APIjson

6. 實例解析瀏覽器

以上六點分爲兩大塊,前3點側重理論,主要讓你們明白WebSocket是什麼,然後3點則結合代碼實戰,加深對WebSocket的認知。

1、WebSocket的前世此生

  Web 應用的信息交互過程一般是客戶端經過瀏覽器發出一個請求,服務器端接收和審覈完請求後進行處理並返回結果給客戶端,而後客戶端瀏覽器將信息呈現出來,這種機制對於信息變化不是特別頻繁的應用尚能相安無事,可是對於那些實時要求比較高的應用來講就顯得捉襟見肘了。咱們須要一種高效節能的雙向通訊機制來保證數據的實時傳輸。有web TCP之稱的WebSocket應運而生,給開發人員提供了一把強有力的武器來解決疑難雜症。

2、WebSocket是什麼?

  其實,從背景介紹中,咱們大體的能夠猜出,WebSocket是幹什麼用的。前面咱們提到,WebSocket有web TCP之稱,既然是TCP,確定是用來作通訊的,可是它又有不一樣的地方,WebSocket做爲HTML5中新增的一種通訊協議,由通訊協議和編程API組成,它可以在瀏覽器和服務器之間創建雙向鏈接,以基於事件的方式,賦予瀏覽器原生的實時通訊能力,來擴展咱們的web應用,增長用戶體驗,提高應用的性 能。何謂雙向?服務器端和客戶端能夠同時發送並響應請求,而再也不像HTTP的請求和響應。

3、爲何使用WebSocket

  在WebSocket出現以前,咱們有一些其它的實時通信方案,比較經常使用的有輪詢,長輪詢,流,還有基於Flash的交換數據的方式,接下來,咱們一一分析一下,各類通訊方式的特色。

①輪詢

  這是最先的一種實現實時web應用的方案;原理比較簡單易懂,就是客戶端以必定的時間間隔向服務器發送請求,以頻繁請求的方式來保持客戶端和服務器端的數據同步。可是問題也很明顯:當客戶端以固定頻率向服務器端發送請求時,服務器端的數據可能並無更新,這樣會帶來不少無謂的請求,浪費帶寬,效率低下。

②長輪詢

  長輪詢是對定時輪詢的改進和提升,目地是爲了下降無效的網絡傳輸。當服務器端沒有數據更新的時候,鏈接會保持一段時間週期直到數據或狀態改變或者時間過時,經過這種機制來減小無效的客戶端和服務器間的交互。固然,若是服務端的數據變動很是頻繁的話,這種機制和定時輪詢比較起來沒有本質上的性能的提升。

③流

  長輪詢是對定時輪詢的改進和提升,目地是爲了下降無效的網絡傳輸。當服務器端沒有數據更新的時候,鏈接會保持一段時間週期直到數據或狀態改變或者時間過時,經過這種機制來減小無效的客戶端和服務器間的交互。固然,若是服務端的數據變動很是頻繁的話,這種機制和定時輪詢比較起來沒有本質上的性能的提升。

④基於Flash的實時通信方式

  Flash有本身的socket實現,這爲實時通訊提供了可能。咱們能夠利用Flash完成數據交換,再利用Flash暴露出相應的接口,方便 JavaScript調用,來達到實時傳輸數據的目的。這種方式比前面三種方式都要高效,並且應用場景比較普遍;由於flash自己的安裝率很高;可是在當前的互聯網環境下,移動終端對flash的支持並很差,以IOS爲主的系統中根本沒有flash的存在,而在android陣營中,雖然有flash的支持,但實際的使用效果差強人意,即便是配置較高的移動設備,也很難讓人滿意。就在前幾天(2012年6月底),Adobe官方宣佈,不在支持 android4.1之後的系統,這基本上宣告了flash在移動終端上的死亡。

下面是輪詢和長輪詢的信息流轉圖:

  對比完四種不一樣的實時通訊方式,不難發現,除了基於flash的方案外,其它三種方式都是用AJAX方式來模擬實時的效果,每次客戶端和服務器端交互時,都是一次完整的HTTP請求和應答的過程,而每一次的HTTP請求和應答都帶有完整的HTTP頭信息,這就增長每次的數據傳輸量,並且這些方案中客 戶端和服務端的編程實現比較複雜。接下來,咱們再來看一下WebSocket,爲何要使用它呢?高效節能,簡單易用。

下圖是來自websocket.org的測試結果:

  在流量和負載增大的狀況下,WebSocket方案相比傳統的Ajax輪詢方案有極大的性能優點;而在開發方面,也十分簡單,咱們只須要實例化WebSocket,建立鏈接,查看是否鏈接成功,而後就能夠發送和相應消息了。 咱們會在後面的實例中去詳細的說明API。

4、搭建WebSocket服務器

  其實,在服務器的選擇上很廣,基本上,主流語言都有WebSocket的服務器端實現,而咱們做爲前端開發工程師,固然要選擇如今比較火熱的NodeJS做爲咱們的服務器端環境了。NodeJS自己並無原生的WebSocket支持,可是有第三方的實現(你們要是有興趣的話,徹底能夠參考WebSocket協議來作本身的實現),咱們選擇了「ws」做爲咱們的服務器端實現。因爲本文的重點是講解WebSocket,因此,對於NodeJS不作過多的介紹,不太熟悉的朋友能夠去參考NodeJS入門指南。安裝好NodeJS以後,咱們須要安裝「ws」,也就是咱們的WebSocket實現,安裝方法很簡單,在終端或者命令行中輸入:npm install ws,等待安裝完成就能夠了。接下來,咱們須要啓動咱們的WebSocket服務。首先,咱們須要構建本身的HTTP服務器,在NodeJS中構建一個簡單的HTTP服務器很簡單,so easy。代碼以下:var app = http.createServer(onRequest ).listen( 8888 );onRequest()做爲回調函數,它的做用是處理請求,而後作出響應,實際上就是根據接收的URL,在服務器上查找相應的資源,最終返回給瀏覽器。在構建了HTTP服務器後,咱們須要啓動WebSocket服務,代碼以下:

var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer( { server : app } );

  從代碼中能夠看出,在初始化WebSocket服務時,把咱們剛纔構建好的HTTP實例傳遞進去就好。到這裏,咱們的服務端代碼差很少也就編寫完成了。怎麼樣?很簡單吧。

5、WebSocket API

上面咱們介紹了WebSocket服務端的知識,接下來,咱們須要編寫客戶端代碼了。在前面咱們說過,客戶端的API也是一如既往的簡單:

  見上圖:ready state中定義的是socket的狀態,分爲connection、open、closing和closed四種狀態,從字面上就能夠區分出它們所表明的狀態。

上圖描述的是WebSocket的事件,分爲onopen、onerror和onclose;

  上圖爲消息的定義,主要是接收和發送消息。注意:能夠發送二進制的數據。因爲WebSocket API(截止到2012年7月)仍是草案,API文檔和上文所描述的會有所不一樣,請以官方文檔爲主,這也是我爲何不詳細描述API中各個屬性的緣由。另一點須要提醒你們的是:在前端開發中,瀏覽器兼容是必不可少的,而WebSocket在主瀏覽器中的兼容仍是不錯的,火狐和Chrome不用說,最新版的支持很是不錯,並且支持二進制數據的發送和接收。可是IE9並不支持,對於國內的大多數應用場景,WebSocket沒法大規模使用。

  之因此選擇百度的統計數據,是由於更加符合國內的實際狀況。圖中所展現的是2012年4月1日到2012年6月30日之間的統計數據,從圖中不難看出IE6.0、奇虎360、IE7.0和IE8.0加起來一共 佔據了77%的市場,FireFox屬於其餘,chrome只有5.72%的份額,再一次告訴咱們,咱們的主戰場依然是IE系。既然是IE系,那麼對於WebSocket在實際app中的應用就基本不可能了。但咱們徹底能夠在chrome、FireFox、以及移動版的IOS瀏覽器中使用它。

6、實例解析

  搭建好了服務端,熟悉了API,接下來,咱們要開始構建咱們的應用了。鑑於WebSocket自身的特色,咱們的第一個demo選擇了比較常見的聊天程序,咱們暫且取名爲chat。說到聊天,你們最早想到的確定是QQ,沒錯,咱們所實現的應用和QQ相似,並且仍是基於web的。由於是demo,咱們的功能比較簡陋,僅實現了最簡單的會話功能。就是啓動WebSocket服務器後,客戶端發起鏈接,鏈接成功後,任意客戶端發送消息,都會被服務器廣播給全部已鏈接的客戶端,包括本身。

  既然須要客戶端,咱們須要構建一個簡單的html頁面,頁面中樣式和元素,你們能夠自由發揮,只要可以輸入消息,有發送按鈕,最後有一個展現消息的區域便可。具體的樣子你們能夠看附件中的demo。寫玩HTML頁面以後,咱們須要添加客戶端腳本,也就是和WebSocket相關的代碼;前面咱們說過,WebSocket的API自己很簡單,因此,咱們的客戶端代碼也很直接,以下:

var wsServer = 'ws://localhost:8888/';
var websocket = new WebSocket(wsServer);
websocket.binaryType = "arraybuffer";
websocket.onopen = onOpen;
websocket.onclose = onClose;
websocket.onmessage = onMessage;
websocket.onerror = onError;

  首先,咱們須要指定WebSocket的服務地址,也就是var wsServer = 'ws://localhost:8888/';而後,咱們實例化WebSocket,new WebSocket(wsServer),剩下的就是指定相應的回調函數了,分別是onOpen,onClose,onMessage和onError,對於我們的實驗應用來講,onopen、onclose、onerror甚至能夠無論,我們重點關注一下onmessage。onmessage()這個回調函數會在客戶端收到消息時觸發,也就是說,只要服務器端發送了消息,咱們就能夠經過onmessage拿到發送的數據,既然拿到了數據,接下去該怎麼玩,就隨便咱們了。請看下面的僞代碼:

function onMessage(evt) {
 var json = JSON.parse(evt.data);
 commands[json.event](json.data);
}

  由於onmessage只接收字符串和二進制類型的數據,若是須要發送json格式的數據,就須要轉換一下格式,把字符串轉換成JSON格式。只要是支持WebSocket,確定原生支持window.JSON,因此,咱們能夠直接使用JSON.parse()和 JSON.stringify()來進行轉換。轉換完成後,咱們就獲得了咱們想要的數據了,接下來所作的工做就是將消息顯示出來。實際上就是

Elements.innerHTML += data + '</br>';

  上面展示了客戶端的代碼,服務器端的代碼相對要簡單一些,由於咱們的服務器端使用的是第三方實現,咱們只須要作一些初始化工做,而後在接收到消息時,將消息廣播出去便可,下面是具體的代碼:

var app = http.createServer( onRequest ).listen( 8888 );
var WebSocketServer = require('ws').Server,
wss = new WebSocketServer( { server : app } );
wss.on('connection', function( ws ) {
    console.log('connection successful!');
    ws.on('message', function( data, flags ){
    console.log(data);
    //do something here
    });
    ws.on('close', function() {
      console.log('stopping client');
   });
});

  咱們能夠經過wss.clients得到當前已鏈接的全部客戶端,而後遍歷,獲得實例,調用send()方法發送數據;

var clients = wss.clients, len = clients.length, i = 0;
  for( ; i <len; i = i + 1 ){
  clients[i].send( msg );
 }

  說到這裏,一個雙向通訊的實例基本完成。

  最後,咱們須要明確一點,WebSocket自己的優勢很明顯,可是做爲一個正在演變中的web規範,咱們必須清楚的認識到WebSocket在構 建應用時的一些風險;雖然自己有不少侷限性,可是這項技術自己確定是大勢所趨,WebSocket在移動終端,在chrome web store都有用武之地,咱們能夠進行大膽的嘗試,讓咱們在技術的革新中不被淘汰。

相關文章
相關標籤/搜索