文章導讀:javascript
1.1 爲何咱們須要WebSocket這樣的實時的通訊協議?html
WebSocket是web通訊方式的一種,像咱們熟知的HTTP協議也是web通訊方式的一種。可是咱們知道HTTP協議是一種無狀態的協議,其服務端自己不具有識別客戶端的能力,必須藉助外部的一些信息好比說session和cookie,才能與特定的客戶端保持通訊。也就是說咱們所發送的每個HTTP的請求都會帶上請求頭中一些相應的信息還有cookie,這明顯會增長咱們傳輸的信息的體量從而帶來必定的網絡延遲,對於一些對通訊的實時性要求比較高的應用來講就是不可忍受的了,好比說聊天程序或者是運行在瀏覽器中的實時小遊戲。最鬱悶的卻仍是這些頭信息和cookie每每對於服務器響應客戶端的請求來講是多餘的,也就是說雖然我每一個請求都帶了這些信息,可是服務器與客戶端的交互過程當中可能根本用不上這些信息。java
爲了改善HTTP請求的這種網絡延遲的狀況,也出現了一些適應不一樣需求的其餘的[web通訊]方式,好比說:輪詢,長輪詢(long-polling),數據流,EventSouce等等,WebSocket即是其中一種。node
實際上大多數基於因特網(或者局域網)的網絡連接一般都包含長鏈接和基於TCP套接字的雙向消息交換。可是TCP協議是屬於最底層的網絡通訊協議了,讓一些不能信任的客戶端腳本去訪問底層的TCP套接字顯然是不太安全的,所以WebSocket實現了一種較爲安全的方案,它容許客戶端腳本在客戶端和支持WebSocket協議的服務器之間建立雙向的套接字鏈接。從而使實時通訊的某些網絡操做變得簡單。git
1.2 WebSocket是如何工做的?github
咱們知道了WebSocket的主要做用是,容許服務器端與客戶端進行全雙工(full-duplex)的實時通訊。這裏有個例子特別好:HTTP協議像發電子郵件,發出後必須等待對方回信;WebSocket則是像打電話,服務器端和客戶端能夠同時向對方發送數據,它們之間存着一條持續打開的數據通道。web
咱們先看一下一個基於WebSocket協議通訊的請求頭和響應頭(下面簡單實例中的一個消息頭):express
其中與WebSocket協議相關的信息:npm
1 Upgrade:websocket-------HTTP1.1協議規定,Upgrade頭信息表示將通訊協議從HTTP/1.1轉向該項所指定的協議; 2 Connection:Upgrade------表示瀏覽器通知服務器,若是容許,就將通訊協議升級到websocket協議; 3 Origin------------------用於驗證瀏覽器域名是否在服務器許可的範圍內; 4 Sec-WebSocket-Key-------則是用於握手協議的密鑰,是base64編碼的16字節隨機字符串;
5 Sec-WebSocket-Accept----是服務器在瀏覽器提供的Sec-WebSocket-Key字符串後面,添加「258EAFA5-E914-47DA-95CA-C5AB0DC85B11」 字符串,而後再取sha-1的hash值。瀏覽器將對這個值進行驗證,以證實確實是目標服務器迴應了webSocket請求;
6.Sec-WebSocket-Location--通常狀況下還有這個響應消息頭用來表示進行通訊的WebSocket網址,這裏面多是由於我例子中設置了127.0.0.1,因此這個信息省略掉了。
客戶端經過一個WebSocket握手的過程創建一個WebSocket鏈接。整個過程看起來是這個樣子的:json
完成握手之後,WebSocket協議就在TCP協議之上,客戶端和服務器端就能夠開始傳送數據了。
websocket協議用ws表示,加密的websocket協議用wss協議,就像普通的HTTP協議用http表示,加密的HTTP協議用https表示同樣。
下面咱們就經過一些實例看一下websocket的不一樣實現是如何應用的。
咱們能夠經過跑起來這個簡單的實例看一下如何編寫運行在瀏覽器中的WebSocket客戶端,而且看它是怎樣與服務器端交互的。
2.1 運行實例
咱們把客戶端代碼和服務端代碼準備好,而後啓動服務器監聽端口,好比說8080,再而後運行咱們的客戶端代碼便可看到效果。
咱們的客戶端代碼寫在html文件中:
[查看源碼]
咱們經過它創建鏈接而且監聽open和messege等事件,與此同時,咱們想要獲得服務器的響應。服務器端的js代碼:
[查看源碼]
這個簡單的websocket服務器使用了[ws模塊],若是沒有安裝過,要先安裝一下:
1 sudo npm install ws
而後在咱們的命令行執行:
1 node simpleWSserver.js
咱們的服務器啓動以後,咱們運行客戶端代碼能夠看到:
瀏覽器:
命令行:
整個過程看起來是這個樣子的:
2.2 運行在瀏覽器中的websocket客戶端
咱們在瀏覽器中的websocket主要作的事情無非是如下幾個:
1 創建鏈接和關閉鏈接 2 發送數據和接收數據 3 處理錯誤
對應的會觸發如下的事件:
1 onopen 2 onmessage 3 onclose 4 onerror
2.2.1 創建鏈接和關閉鏈接
一般咱們新建了一個WebSocket的實例就能夠創建一個鏈接:
1 if(window.WebSocket != undefined) { 2 var socket = new WebSocket("ws://127.0.0.1:8080/"); 3 }
創建鏈接以後的WebSocket實例有一個readyState屬性,用來標識當前的狀態:
0-正在鏈接 1-鏈接成功 2-正在關閉 3-關閉成功
鏈接成功後會觸發onopen事件,這時咱們就能夠向服務器發送數據了:
1 var onOpen = function() { 2 console.log("Socket opened."); 3 socket.send("Hi, Server!"); 4 } 5 socket.onopen = onOpen;
要是關閉鏈接的話就會出發onclose事件:
1 var onClose = function() { 2 console.log("Socket closed."); 3 } 4 socket.onclose = onClose;
2.2.2 發送數據和接收數據
在鏈接創建成功後觸發的onopen事件中咱們經過send()方法發送數據給服務器:
1 socket.send("Hi, Server!");
除了發送字符串類型的數據,也可使用 Blob 或 ArrayBuffer 對象發送二進制數據。不只如此,咱們還能夠發送JSON數據:
1 var onOpen = function() { 2 var msg = { 3 type: "message", 4 text: "something", 5 id: "number", 6 date: Date.now() 7 }; 8 9 // Send the msg object as a JSON-formatted string. 10 socket.send(JSON.stringify(msg)); 11 } 12 socket.onopen = onOpen;
這時會觸發服務器端的message事件:
1 ws.on('message', function incoming(message) { 2 console.log('received: %s', message); 3 });
同時,服務器端發來信息的時候:
1 ws.send('something');
也會觸發客戶端的onmessage事件:
1 var onMessage = function(data) { 2 console.log("We get signal:"); 3 console.log(data); 4 } 5 socket.onmessage = onMessage;
2.2.3 處理錯誤
發生的錯誤會觸發onerror事件:
1 var onError = function() { 2 console.log("We got an error."); 3 } 4 socket.onerror = onError;
WebSocket在Node中的實現[WebSocket-Node]使咱們能夠在Nodejs中使用websokcet開發客戶端和服務器端實時交互的應用程序。咱們能夠運行客戶端和服務器實時交換隨機數的例子看看它是怎麼工做的:
啓動服務器:
node socketserver.js
[查看源碼]
啓動客戶端:
node socketclient.js
[查看源碼]
如今很流行的websocket的實現socket.io一樣包括客戶端和服務器端兩部分。它不只簡化了接口,使得操做更容易,並且對於那些不支持WebSocket的瀏覽器,會自動降爲Ajax鏈接,最大限度地保證了兼容性。它的目標是統一通訊機制,使得全部瀏覽器和移動設備均可以進行實時通訊。
4.1 socket.io與WebSocket的區別在哪裏呢?
websocket是瀏覽器對象,websocket api是瀏覽器提供給咱們的用於瀏覽器和服務器實時通訊的接口。
websocket在node中的實現使咱們能夠開發服務端程序時使用websocket的特性。
在咱們使用websocket的時候,由於他是瀏覽器提供的接口,因此會涉及到一些兼容性和支持性的問題。若是咱們對程序所運行的環境或侷限不是那麼瞭解的化,那麼可能會出現問題:
[Differences between socket.io and websocket] 。而socket.io則是進化了的websocket api。socket.io創建在websocket之上,它在合適的時候使用websocket。
4.2 socket.io實現聊天室
使用websocket或socket.io能夠從一個簡單的聊天室程序開始。對於socket.io來講,這很是容易。
基於node,這裏使用express和socket.io:
1 npm install --save express@4.10.2 2 npm install --save socket.io
那麼咱們就能夠開始寫聊天程序了。它須要的就是一個客戶端的聊天窗口和一個用來接收消息和分發消息的服務器。
咱們須要三個文件,分別新建:package.json,index.js,index.html.
package.json:
index.js:
index.html:
先運行:
node index.js
在打開兩個http://localhost:3000的窗口就能夠開始聊天了:
[查看源代碼]
socket.io官網上有很詳細的使用方法和教程:[socket.io doc]
[web通訊]
[WebSocket-Node implementation]