WebSocket介紹和使用nodejs+socket.io搭建服務器和客戶端

WebSocket介紹與原理

WebSocket protocol 是HTML5一種新的協議。它實現了瀏覽器與服務器全雙工通信(full-duplex)。一開始的握手需要藉助HTTP請求完成。
——百度百科

目的:即時通訊,替代輪詢

網站上的即時通訊是很常見的,比如網頁的QQ,聊天系統等。按照以往的技術能力通常是採用輪詢、Comet技術解決。

HTTP協議是非持久化的,單向的網絡協議,在建立連接後只允許瀏覽器向服務器發出請求後,服務器才能返回相應的數據。當需要即時通訊時,通過輪詢在特定的時間間隔(如1秒),由瀏覽器向服務器發送Request請求,然後將最新的數據返回給瀏覽器。這樣的方法最明顯的缺點就是需要不斷的發送請求,而且通常HTTP request的Header是非常長的,爲了傳輸一個很小的數據 需要付出巨大的代價,是很不合算的,佔用了很多的寬帶。

缺點:會導致過多不必要的請求,浪費流量和服務器資源,每一次請求、應答,都浪費了一定流量在相同的頭部信息上

然而WebSocket的出現可以彌補這一缺點。在WebSocket中,只需要服務器和瀏覽器通過HTTP協議進行一個握手的動作,然後單獨建立一條TCP的通信通道進行數據的傳送。

原理

WebSocket同HTTP一樣也是應用層的協議,但是它是一種雙向通信協議,是建立在TCP之上的。

連接過程 —— 握手過程

  • 瀏覽器、服務器建立TCP連接,三次握手。這是通信的基礎,傳輸控制層,若失敗後續都不執行。
  • TCP連接成功後,瀏覽器通過HTTP協議向服務器傳送WebSocket支持的版本號等信息。(開始前的HTTP握手)
  • 服務器收到客戶端的握手請求後,同樣採用HTTP協議回饋數據。
  • 當收到了連接成功的消息後,通過TCP通道進行傳輸通信。

WebSocket與HTTP的關係

相同點

  • 都是一樣基於TCP的,都是可靠性傳輸協議。
  • 都是應用層協議。

不同點

  • WebSocket是雙向通信協議,模擬Socket協議,可以雙向發送或接受信息。HTTP是單向的。
  • WebSocket是需要握手進行建立連接的。

聯繫

WebSocket在建立握手時,數據是通過HTTP傳輸的。但是建立之後,在真正傳輸時候是不需要HTTP協議的。

WebSocket與Socket的關係

Socket其實並不是一個協議,而是爲了方便使用TCP或UDP而抽象出來的一層,是位於應用層和傳輸控制層之間的一組接口。

Socket是應用層與TCP/IP協議族通信的中間軟件抽象層,它是一組接口。在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket接口後面,對用戶來說,一組簡單的接口就是全部,讓Socket去組織數據,以符合指定的協議。

這裏寫圖片描述

主機 A 的應用程序要能和主機 B 的應用程序通信,必須通過 Socket 建立連接,而建立 Socket 連接必須需要底層 TCP/IP 協議來建立 TCP 連接。建立 TCP 連接需要底層 IP 協議來尋址網絡中的主機。我們知道網絡層使用的 IP 協議可以幫助我們根據 IP 地址來找到目標主機,但是一臺主機上可能運行着多個應用程序,如何才能與指定的應用程序通信就要通過 TCP 或 UPD 的地址也就是端口號來指定。這樣就可以通過一個 Socket 實例唯一代表一個主機上的一個應用程序的通信鏈路了。

WebSocket則是一個典型的應用層協議。

區別

Socket是傳輸控制層協議,WebSocket是應用層協議。

HTML5與WebSocket的關係

WebSocket API 是 HTML5 標準的一部分, 但這並不代表 WebSocket 一定要用在 HTML 中,或者只能在基於瀏覽器的應用程序中使用。
實際上,許多語言、框架和服務器都提供了 WebSocket 支持,例如:

  • 基於 C 的 libwebsocket.org
  • 基於 Node.js 的 Socket.io
  • 基於 Python 的 ws4py
  • 基於 C++ 的 WebSocket++
  • Apache 對 WebSocket 的支持: Apache Module mod_proxy_wstunnel
  • Nginx 對 WebSockets 的支持: NGINX as a WebSockets Proxy 、 NGINX Announces Support for WebSocket Protocol 、WebSocket proxying
  • lighttpd 對 WebSocket 的支持:mod_websocket

WebSocket 機制

以下簡要介紹一下 WebSocket 的原理及運行機制。

WebSocket 是 HTML5 一種新的協議。它實現了瀏覽器與服務器全雙工通信,能更好的節省服務器資源和帶寬並達到實時通訊,它建立在 TCP 之上,同 HTTP 一樣通過 TCP 來傳輸數據,但是它和 HTTP 最大不同是:

WebSocket 是一種雙向通信協議,在建立連接後,WebSocket 服務器和 Browser/Client Agent 都能主動的向對方發送或接收數據,就像 Socket 一樣;
WebSocket 需要類似 TCP 的客戶端和服務器端通過握手連接,連接成功後才能相互通信。
非 WebSocket 模式傳統 HTTP 客戶端與服務器的交互如下圖所示:

圖 1. 傳統 HTTP 請求響應客戶端服務器交互圖
這裏寫圖片描述

使用 WebSocket 模式客戶端與服務器的交互如下圖:

圖 2.WebSocket 請求響應客戶端服務器交互圖
這裏寫圖片描述

上圖對比可以看出,相對於傳統 HTTP 每次請求-應答都需要客戶端與服務端建立連接的模式,WebSocket 是類似 Socket 的 TCP 長連接的通訊模式,一旦 WebSocket 連接建立後,後續數據都以幀序列的形式傳輸。在客戶端斷開 WebSocket 連接或 Server 端斷掉連接前,不需要客戶端和服務端重新發起連接請求。在海量併發及客戶端與服務器交互負載流量大的情況下,極大的節省了網絡帶寬資源的消耗,有明顯的性能優勢,且客戶端發送和接受消息是在同一個持久連接上發起,實時性優勢明顯。

我們再通過客戶端和服務端交互的報文看一下 WebSocket 通訊與傳統 HTTP 的不同:

在客戶端,new WebSocket 實例化一個新的 WebSocket 客戶端對象,連接類似 ws://yourdomain:port/path 的服務端 WebSocket URL,WebSocket 客戶端對象會自動解析並識別爲 WebSocket 請求,從而連接服務端端口,執行雙方握手過程,客戶端發送數據格式類似:
清單 1.WebSocket 客戶端連接報文

GET /webfin/websocket/ HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg==
Origin: 
http://localhost
:8080
Sec-WebSocket-Version: 13

可以看到,客戶端發起的 WebSocket 連接報文類似傳統 HTTP 報文,”Upgrade:websocket”參數值表明這是 WebSocket 類型請求,“Sec-WebSocket-Key”是 WebSocket 客戶端發送的一個 base64 編碼的密文,要求服務端必須返回一個對應加密的“Sec-WebSocket-Accept”應答,否則客戶端會拋出“Error during WebSocket handshake”錯誤,並關閉連接。

服務端收到報文後返回的數據格式類似:

清單 2.WebSocket 服務端響應報文

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=

“Sec-WebSocket-Accept”的值是服務端採用與客戶端一致的密鑰計算出來後返回客戶端的,“HTTP/1.1 101 Switching Protocols”表示服務端接受 WebSocket 協議的客戶端連接,經過這樣的請求-響應處理後,客戶端服務端的 WebSocket 連接握手成功, 後續就可以進行 TCP 通訊了。

在開發方面,WebSocket API 也十分簡單,我們只需要實例化 WebSocket,創建連接,然後服務端和客戶端就可以相互發送和響應消息,在下文 WebSocket 實現及案例分析部分,可以看到詳細的 WebSocket API 及代碼實現。

WebSocket 客戶端 API

對於 WebSocket 客戶端,主流的瀏覽器(包括 PC 和移動終端)現已都支持標準的 HTML5 的 WebSocket API,這意味着客戶端的 WebSocket JavaScirpt 腳本具備良好的一致性和跨平臺特性,以下列舉了常見的瀏覽器廠商對 WebSocket 的支持情況:
表 2.WebSocket 客戶端支持

瀏覽器 支持情況
Chrome Chrome version 4+支持
Firefox Firefox version 5+支持
IE IE version 10+支持
Safari IOS 5+支持
Android Brower Android 4.5+支持

客戶端 WebSocket API 基本上已經在各個主流瀏覽器廠商中實現了統一,因此使用標準 HTML5 定義的 WebSocket 客戶端的 JavaScript API 即可,當然也可以使用業界滿足 WebSocket 標準規範的開源框架,如 Socket.io。

以下以一段代碼示例說明 WebSocket 的客戶端實現:

清單 5.WebSocket 客戶端 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!”);};

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

第二行到第五行爲 WebSocket 對象註冊消息的處理函數,WebSocket 對象一共支持四個消息 onopen, onmessage, onclose 和 onerror,有了這 4 個事件,我們就可以很容易很輕鬆的駕馭 WebSocket。

當 Browser 和 WebSocketServer 連接成功後,會觸發 onopen 消息;如果連接失敗,發送、接收數據失敗或者處理數據出現錯誤,browser 會觸發 onerror 消息;當 Browser 接收到 WebSocketServer 發送過來的數據時,就會觸發 onmessage 消息,參數 evt 中包含 Server 傳輸過來的數據;當 Browser 接收到 WebSocketServer 端發送的關閉連接請求時,就會觸發 onclose 消息。我們可以看出所有的操作都是採用異步回調的方式觸發,這樣不會阻塞 UI,可以獲得更快的響應時間,更好的用戶體驗。

nodejs之socket.io模塊——實現了websocket協議

Nodejs實現websocket的4種方式:socket.io、WebSocket-Node、faye-websocket-node、node-websocket-server,這裏主要使用的是socket.io。

服務端

1.首先安裝socket.io

npm  install  socket.io

2.server.js

var app = require('http').createServer(handler),   
    io = require('socket.io').listen(app),   
    fs = require('fs')  

app.listen(8080);  
io.set('log level', 1);//將socket.io中的debug信息關閉  

function handler (req, res) {  
  fs.readFile(__dirname + '/index.html',function (err, data) {    
    if (err) {  
      res.writeHead(500);  
      return res.end('Error loading index.html');  
    }      
    res.writeHead(200, {'Content-Type': 'text/html'});      
    res.end(data);  
  });  
}  

io.sockets.on('connection', function (socket) {  
    socket.emit('news', { hello: 'world' });  
    socket.on('my other event', function (data) {  
      console.log(data);  
    });  
});  

客戶端

1.websocket是html5標準,瀏覽器內部已經支持了,其編程接口大致有connect、close、open、send幾個接口,如果要使用瀏覽器原生的方式編寫websocket,比較繁瑣,所以可以下載一個客戶端庫方便編程,這裏使用的是socket.io客戶端庫,點擊打開鏈接

2.index.html

<!DOCTYPE html>  
<html lang="en">  
<head>  
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
    <title>Ssocket</title>  
    <script type="text/javascript" src="https://cdn.socket.io/socket.io-1.3.5.js"></script>       
</head>  

<body>  
    <script type="text/javascript">  
      var socket = io.connect('http://localhost:8080');       
      socket.on('news', function (data) {      
        alert(data.hello);  
        socket.emit('my other event', { my: 'data' });  
      });  
    </script>  

</body>  
</html>  

測試

啓動服務端nodejs代碼:node server.js

在瀏覽器輸入 http://localhost:8080/index.html
瀏覽器打印出: world
命令行打印出:{ my: ‘data’ }

參考:
https://blog.csdn.net/wwd0501/article/details/54582912
https://www.cnblogs.com/merray/p/7918977.html
https://blog.csdn.net/liuxiao723846/article/details/47341929

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章