淺談webscoket原理及其應用

lzg9527發表於2019-12-03

什麼是 webSocket

WebSocket 是一種在單個 TCP 連線上進行全雙工通訊的協議。使得客戶端和伺服器之間的資料交換變得更加簡單,允許服務端主動向客戶端推送資料。

在 WebSocket API 中,瀏覽器和伺服器只需要完成一次握手,兩者之間就直接可以建立永續性的連線,並進行雙向資料傳輸。

WebSocket 解決了什麼問題:

在不使用 WebSocket 時,如果我們需要建立一條長連線,有以下幾種方法:

  • 輪詢
  • 長輪詢(常用)
  • SSE(Server Send Event)

當出現類似體育賽事、聊天室、實時位置之類的場景時,客戶端要獲取伺服器端的變化,就只能通過輪詢(定時請求)來了解伺服器端有沒有新的資訊變化。WebSocket 的出現,讓伺服器端可以主動向伺服器端傳送資訊,使得瀏覽器具備了實時雙向通訊的能力,這就是 WebSocket 解決的問題

  • 頻寬問題:WebSocket 相對於 HTTP 來說協議頭更加小,同時按需傳遞。
  • 資料實時性問題:WebSocket 相對於輪詢和長輪詢來說,能夠實時傳遞資料,延遲更小。
  • 狀態問題:相較於 HTTP 的無狀態請求,WebSocket 在建立連線後能夠維持特定的狀態。

WebSocket 與 HTTP 對比

淺談webscoket原理及其應用

基本使用

客戶端

const ws = new WebSocket('ws://localhost:8888')

ws.onopen = () => {
  console.log('WebSocket onopen')
}

ws.onmessage = e => {
  console.log(e)
  console.log(e.data)
}

ws.onclose = e => {
  console.log('WebSocket onclose')
}

ws.onerror = e => {
  console.log('WebSocket onerror')
}
複製程式碼
  • WebSocket.onopen: 連線成功後呼叫
  • WebSocket.onmessage: 當接收到伺服器訊息時呼叫
  • WebSocket.onclose: 連線關閉後呼叫
  • WebSocket.onerror: 發生錯誤後呼叫

服務端例子(koa)

const Koa = require('koa')
const WebSocket = require('ws')

const app = new Koa()
const ws = new WebSocket.Server({ port: 8888 })

ws.on('connection', ws => {
  console.log('server connection')

  ws.on('message', msg => {
    console.log('server receive msg:', msg)
  })

  ws.send('Information from the server')
})

app.listen(3000)
複製程式碼

WebSocket 可以傳遞 String、ArrayBuffer 和 Blob 三種資料型別,因此在收到訊息時可能是其中的任意一種。其中,String 和 ArrayBuffer 使用的最多。

  • 如果是 String 型別,直接通過字串處理函式即可進行相關轉換,如 JSON 等格式。
  • 如果是二進位制 blob 型別,則需要使用 ArrayBuffer 和 DataView 來進行處理,下面簡單介紹。

二進位制資料包括:blob 物件和 Arraybuffer 物件,所以我們需要分開來處理。

// 接收資料
ws.onmessage = function(event) {
  if (event.data instanceof ArrayBuffer) {
    // 判斷 ArrayBuffer 物件
  }
  if (event.data instanceof Blob) {
    // 判斷 Blob 物件
  }
}

// 傳送 Blob 物件的例子
let file = document.querySelector('input[type="file"]').files[0]
ws.send(file)
// 傳送 ArrayBuffer 物件的例子
var img = canvas_context.getImageData(0, 0, 400, 320)
var binary = new Uint8Array(img.data.length)
for (var i = 0; i < img.data.length; i++) {
  binary[i] = img.data[i]
}
ws.send(binary.buffer)
複製程式碼

webSocket.bufferedAmount 屬性,表示還有多少位元組的二進位制資料沒有傳送出去 如果傳送的二進位制資料很大的話,可以這樣判斷

var data = new ArrayBuffer(10000000)
socket.send(data)
if (socket.bufferedAmount === 0) {
  // 傳送完畢
} else {
  // 傳送還沒結束
}
複製程式碼

總結 WebSocket 的優點

  • 雙向通訊(一開始說的,也是最重要的一點)。
  • 資料格式比較輕量,效能開銷小,通訊高效
  • 協議控制的資料包頭部較小,而 HTTP 協議每次通訊都需要攜帶完整的頭部
  • 更好的二進位制支援
  • 沒有同源限制,客戶端可以與任意伺服器通訊
  • 與 HTTP 協議有著良好的相容性。預設埠也是 80 和 443,並且握手階段採用 HTTP 協議,因此握手時不容易遮蔽,能通過各種 HTTP 代理伺服器

相關文章