1. 程式人生 > 其它 >Netty學習之實戰WebSocket框架

Netty學習之實戰WebSocket框架

說到WebSocket技術,其實源於伺服器推送技術,在現實中很多時候需要的資料是不斷變化的,比如股市資料、聊天軟體,因此就需要一種客戶端想要在不重新整理頁面的情況下實時獲取到伺服器端最新資料的技術,而以往的資料獲取都是基於客戶端主動請求,服務端返回對應資料。因此就有了伺服器推送技術。

  伺服器推送技術主要由以下幾種:Ajax短輪詢、Ajax長輪詢、SSE、HTTP流、WebSocket。

一、伺服器推送技術

  1、Ajax短輪詢

  實現簡單,客戶端(瀏覽器)定時向伺服器端傳送請求,獲取最新的資料。可以通過在一個定時器中觸發ajax請求來實現。

  優點:實現非常簡單,JS端進行一些更改即可,無需後端服務任何改動;

  缺點:輪詢的間隔過長,會導致使用者不能及時接收到更新的資料;輪詢的間隔過短,會導致查詢請求過多,增加伺服器端的負擔。

          

  程式碼如下:

//每兩秒觸發一次ajax請求,獲取最新的資料
setInterval(function(){
   //do some ajax call here to retrieve latest data
},2000);

  2、Ajax長輪詢

  在Ajax輪詢的基礎上做的一點改進,在後端資料沒有更新的時候不再返回空響應,而且後端一直儲存連線,直到後端有資料變化,則相應請求並且關閉連線,前端收到資料,馬上再次向後端發起請求,並處理剛剛收到的資料。

  • 客戶端發起一個請求到伺服器端(http request)
  • 伺服器端一直保持連線開啟,直到有資料資料可傳送給客戶端,再返回這個請求(http response)
  • 客戶端收到伺服器端返回的資料後,處理資料,並立馬發起一個新的請求
            

  優點:

  • 可以及時獲取到最新的資料
  • 相較於輪詢策略,減少了請求數量

  缺點:

  伺服器端要一直保持連線,不能釋放,由於一個伺服器能夠處理的連線數有限,當達到伺服器處理的上限的時候,伺服器將無法響應新的請求

  程式碼如下:  

function async() {
    $.ajax({
        url: 'http://api.3g.qq.com',
        success: function() {
            async();
            //success code
        }
    });
}

  Servlet3 裡的非同步任務以及Spring帶來的DeferedResult都是使用Ajax的長連線。

  3、HTTP流

  HTTP流區別於輪詢和長輪詢方法,它在客戶端網頁的生命週期內,只需要使用一個HTTP連線,也就是隻會向伺服器傳送一個請求,對於這個請求,伺服器會保持HTTP連線(不返回response),然後週期性的向瀏覽器傳送資料。
//server端示例(nodejs)
let express = require("express");
let app = express();

app.use(express.static("resources"));
app.get("/httpstream",function(req, res){
    var x = 0;
    res.setHeader('Connection', 'Transfer-Encoding');
  res.setHeader('Content-Type', 'text/html; charset=utf-8');
  res.setHeader('Transfer-Encoding', 'chunked');//宣告資料傳輸編碼為chunked,讓瀏覽器及時處理
    setInterval(function(){
        res.write(x+++"|"); //每隔2s向客戶端傳送一次資料
    },2000);
});

app.listen(3000);

  伺服器端接收到請求後,每隔兩秒向客戶端輸出一點文字,但是不會使用res.end()或者res.send()結束當前http請求。

//客戶端示例js
var xhr = new XMLHttpRequest();
var received = 0;
var result = "";
xhr.open("get","/httpstream",true);
xhr.onreadystatechange = function () {
  if (xhr.readyState == 3) { //readystate 3 表示正在解析資料
    result = xhr.responseText.substring(received);//擷取最新的資料
    received += result.length;
    console.log(result);
  }
}
xhr.send();
  隨著不斷從伺服器端接收到資料,客戶端的readyState會週期性的變成3responseText包含所有的資料來源。通過received來記錄之前已經處理過的資料長度,然後在responseText中擷取最新的資料。             

  優點:

  頁面的整個生命週期內,只需要建立一個http連線。

  缺點:

  • 如果接入的客戶端過多,伺服器端會因為http連線有限而無法為新的客戶端提供服務。
  • 客戶端接收到的資料流會越來越大,最終可能會引發頁面的效能問題

  4、SSE(Server-Sent-Events)

  SSE(Server-Sent Events)是基於HTTP實現的一套伺服器向客戶端傳送資料的API。他是針對上面說到的三種方法(輪詢,長輪詢,HTTP流)的一個標準API實現。使用SSE API可以建立到伺服器端的單向連線,伺服器可以通過這個連線傳送任意資料。它有以下特點:

  • 斷開自動連線
  • 伺服器響應的MIME型別必須是text/event-stream
  • 需要瀏覽器API支援(參考瀏覽器相容性)

            

  使用方法如下:

//客戶端js
var source = new EventSource(url);
//建立連線時觸發
source.onopen = function () {
  //do something here
};
//從伺服器端接收到新的事件時觸發
source.onmessage = function (event) {
  var data = event.data; //伺服器返回的資料存放在event.data中
};
//連線異常時觸發
source.onerror = function () {
  //do something here
};

  客戶端建立一個EventSource物件,繫結到對應的url,然後監聽該物件的onmessage事件就可以獲取到最新的資料。

//server端示例(nodejs)
let express = require("express");
let app = express();

app.use(express.static("resources"));
app.get("/httpstream",function(req, res){
    var x = 0;
  res.writeHead(200, {
      "Content-Type":"text/event-stream",
      "Cache-Control":"no-cache",
      "Connection":"keep-alive"
    });
  //每個1s往客戶端傳送一條資料
  setInterval(function(){
      res.write("data: " + x++ + "\n\n");//傳送的資料格式必須是"data: <內容>/n/n"
  },1000);
});

app.listen(3000);

  5、WebSocket

  5.1、什麼是WebSocket?

  WebSocket是html5出來的協議,http是不支援久連結的,WebSocket其實是一個新協議,實現了與客戶端與伺服器雙向,基於訊息的文字或二進位制資料通訊;適合於對資料的實時性要求比較強的場景,如即時通訊、直播、共享桌面;後端需要單獨實現;客戶端並不是所有瀏覽器都支援。

  5.2、WebSocket通訊協議兩部分?

  • 一是開放性HTTP握手連線協商連線引數,在交換資料之前,客戶端必須與伺服器協商適當的引數以建立連線
  • 二是二進位制訊息分幀機制(接收訊息的文字和二進位制資料傳輸)。WebSocket協議提供了很多強大的特性:基於訊息的通訊、自定義的二進位制分幀層、子協議協商、可選的協議擴充套件,等等。

  5.3、什麼是HTTP協議升級?

  即先通過HTTP實現握手,然後進行協議升級,後續使用WebSocket協議進行通訊。

  WebSocket和http協議有一定的交集,前端跟服務端建立websocket連線需要先發送一個htt請求,並再請求資料裡表明協議需要升級為websocket。應用層通過sec-websocket-key和sec-websocket-accept標識一個唯一的websocket通道。

                      

  如下所示:

          

  最後,前述握手完成後,如果握手成功,該連線就可以用作雙向通訊通道交換WebSocket訊息。到此,客戶端與伺服器之間不會再發生HTTP通訊,一切由WebSocket協議接管。  

  5.4、如何協議升級

  WebSocket是通過WebSocketServerHandshaker 處理服務端的websocket協議升級。

          

       

  handshaker.handshake的本質是在當前pipeline新增websocket協議的編解碼器,並移除http協議編解碼器。

  5.5、Websocket訊息實體-WebSocketFrame

  WebSocket支援多種訊息實體,可以用在不同場景,例如文字、流式二進位制資料、心跳檢測等。如下圖所示,不同的訊息實體實現類實現不同的訊息功能。

  

  5.6、什麼是WebSocket子協議-STOMP

  文字定向訊息協議:STOMP協議的前身是TTMP協議(一個簡單的基於文字的協議),專為訊息中介軟體設計。它的簡單性恰巧可以用於定義webSocket的訊息體格式. STOMP協議很多MQ都已支援。

二、WebSocket專案實戰演練

  本博文是一個聊天室的專案實戰,程式碼來自於原始碼學院,GitHub地址為:https://github.com/kosamino/netty-websocket-server

  程式碼結構及功能如下圖所示:

              

  系統流程圖如下圖所示:

  另附另一個其餘博主的WebSocket專案實戰:Netty+WebSocket 獲取火幣交易所資料專案