首頁 >web前端 >前端問答 >十分鐘快速了解websocket! !

十分鐘快速了解websocket! !

青灯夜游
青灯夜游轉載
2021-02-15 09:18:193104瀏覽

十分鐘快速了解websocket! !

什麼是WebSocket

定義

Websocket是持久化的網路通訊協議,可以在單一TCP 連接上進行全雙工通訊,沒有了RequestResponse的概念,兩者地位完全平等,連接一旦建立,客戶端和服務端之間實時可以進行雙向資料傳輸

關聯和區別

  • HTTP
  1. #HTTP是非持久的協議,客戶端想知道服務端的處理進度只能透過不停地使用Ajax進行輪詢或採用long poll 的方式來,但是前者對伺服器壓力大,後者則會因為一直等待Response造成阻塞
  2. 雖然http1.1預設開啟了keep-alive長連線保持了這個TCP通道使得在一個HTTP連線中,可以發送多個Request,接收多個Response,但一個request只能有一個response。而且這個response也是被動的,不能主動發起。
  3. websocket雖然是獨立於HTTP的一種協議,但是websocket必須依賴HTTP 協議進行一次握手(在握手階段是一樣的),握手成功後,資料就直接從TCP通道傳輸,與HTTP 無關了,可以用一張圖理解兩者有交集,但並不是全部。
  • socket
  1. #socket也稱為套接字,與HTTP和WebSocket不一樣,socket不是協議,它是在程式層面上對傳輸層協定(可以主要理解為TCP/IP)的介面封裝。可以理解為一個能夠提供端對端的通訊的呼叫介面(API)
  2. 對於程式設計師而言,其需要在A 端建立一個socket 實例,並為此實例提供其所要連接的B 端的IP位址和連接埠號,而在B 端建立另一個socket 實例,並且綁定本機連接埠號碼來進行監聽。當 A 和 B 建立連線後,雙方就建立了一個端對端的 TCP 連接,因此可以進行雙向通訊。 WebSocekt借鑒了socket 的思想,為client 和server 之間提供了類似的雙向通訊機制

應用程式場景

WebSocket可以做彈幕、訊息訂閱、多玩家遊戲、協同編輯、股票基金即時報價、視訊會議、線上教育、聊天室等應用程式即時監聽服務端變更

Websocket握手

  • Websocket握手請求訊息:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

下面是與傳統HTTP 封包不同的地方:

Upgrade: websocket
Connection: Upgrade

表示發起的是WebSocket 協定

Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

Sec-WebSocket-Key 是由瀏覽器隨機產生的,驗證是否可以進行Websocket通信,防止惡意或無意的連接。

Sec_WebSocket-Protocol 是使用者自訂的字串,用來識別服務所需的協定

Sec-WebSocket-Version# 表示支持的WebSocket 版本。

  • 伺服器回應:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

101 回應碼 表示要轉換協定。

Connection: Upgrade 表示升級新協定請求。

Upgrade: websocket 表示升級為 WebSocket 協定。

Sec-WebSocket-Accept 是經過伺服器確認,並且加密後的 Sec-WebSocket-Key。用來證明客戶端和伺服器之間能進行通訊了。

Sec-WebSocket-Protocol 表示最終使用的協定。

至此,客戶端和伺服器握手成功建立了Websocket連接,HTTP已經完成它所有工作了,接下來就是完全按照Websocket協定進行通信了。

關於Websocket

WebSocket心跳

可能會有一些未知情況導致SOCKET斷開,而客戶端和服務端卻不知道,需要客戶端定時發送一個心跳Ping 讓服務端知道自己在線,而服務端也要回復一個心跳Pong告訴客戶端自己可用,否則視為斷開

WebSocket狀態

WebSocket 物件中的readyState屬性有四種狀態:

  • 0: 表示正在連線
  • 1: 表示連線成功,可以通訊了
  • 2: 表示連線正在關閉
  • 3: 表示連線已關閉,或開啟連線失敗

#WebSocket實務

服務端接收傳送訊息

WebSocket的服務端部分,本文會以Node.js建構

安裝express和負責處理WebSocket協定的ws

npm install express ws

安裝成功後的package.json:

接著在根目錄建立server.js檔案:

//引入express 和 ws
const express = require('express');
const SocketServer = require('ws').Server;
//指定开启的端口号
const PORT = 3000;
// 创建express,绑定监听3000端口,且设定开启后在consol中提示
const server = express().listen(PORT, () => console.log(`Listening on ${PORT}`));
// 将express交给SocketServer开启WebSocket的服务
const wss = new SocketServer({ server });
//当 WebSocket 从外部连接时执行
wss.on('connection', (ws) => {
  //连接时执行此 console 提示
  console.log('Client connected');
  // 对message设置监听,接收从客户端发送的消息
  ws.on('message', (data) => {
    //data为客户端发送的消息,将消息原封不动返回回去
    ws.send(data);
  });
  // 当WebSocket的连接关闭时执行
  ws.on('close', () => {
    console.log('Close connected');
  });
});

執行node server.js啟動服務,連接埠開啟後會執行監聽時間列印提示,說明服務啟動成功

在開啟WebSocket後,服務端會在message中監聽,接收參數data捕獲客戶端發送的訊息,然後使用send發送訊息

客戶端接收發送訊息

分別在根目錄建立index.html和index.js檔

  • index.html
<html>
  <body>
    <script src="./index.js"></script>
  </body>
</html>
  • index.js
// 使用WebSocket的地址向服务端开启连接
let ws = new WebSocket(&#39;ws://localhost:3000&#39;);
// 开启后的动作,指定在连接后执行的事件
ws.onopen = () => {
  console.log(&#39;open connection&#39;);
};
// 接收服务端发送的消息
ws.onmessage = (event) => {
  console.log(event);
};
// 指定在关闭后执行的事件
ws.onclose = () => {
  console.log(&#39;close connection&#39;);
};

上面的url就是本机node开启的服务地址,分别指定连接(onopen),关闭(onclose)和消息接收(onmessage)的执行事件,访问html,打印ws信息

打印了open connection说明连接成功,客户端会使用onmessage处理接收

其中event参数包含这次沟通的详细信息,从服务端回传的消息会在event的data属性中。

手动在控制台调用send发送消息,打印event回传信息:

服务端定时发送

上面是从客户端发送消息,服务端回传。我们也可以通过setInterval让服务端在固定时间发送消息给客户端:

server.js修改如下:

//当WebSocket从外部连接时执行
wss.on(&#39;connection&#39;, (ws) => {
  //连接时执行此 console 提示
  console.log(&#39;Client connected&#39;);
+  //固定发送最新消息给客户端
+  const sendNowTime = setInterval(() => {
+    ws.send(String(new Date()));
+  }, 1000);
-  //对message设置监听,接收从客户端发送的消息
-  ws.on(&#39;message&#39;, (data) => {
-    //data为客户端发送的消息,将消息原封不动返回回去
-    ws.send(data);
-  });
  //当 WebSocket的连接关闭时执行
  ws.on(&#39;close&#39;, () => {
    console.log(&#39;Close connected&#39;);
  });
});

客户端连接后就会定时接收,直至我们关闭websocket服务

多人聊天

如果多个客户端连接按照上面的方式只会返回各自发送的消息,先注释服务端定时发送,开启两个窗口模拟:

如果我们要让客户端间消息共享,也同时接收到服务端回传的消息呢?

我们可以使用clients找出当前所有连接中的客户端 ,并通过回传消息发送到每一个客户端 中:

修改server.js如下:

...
//当WebSocket从外部连接时执行
wss.on(&#39;connection&#39;, (ws) => {
  //连接时执行此 console 提示
  console.log(&#39;Client connected&#39;);
-  //固定发送最新消息给客户端
-  const sendNowTime = setInterval(() => {
-    ws.send(String(new Date()));
- }, 1000);
+  //对message设置监听,接收从客户端发送的消息
+   ws.on(&#39;message&#39;, (data) => {
+    //取得所有连接中的 客户端
+    let clients = wss.clients;
+    //循环,发送消息至每个客户端
+    clients.forEach((client) => {
+      client.send(data);
+    });
+   });
  //当WebSocket的连接关闭时执行
  ws.on(&#39;close&#39;, () => {
    console.log(&#39;Close connected&#39;);
  });
});

这样一来,不论在哪个客户端发送消息,服务端都能将消息回传到每个客户端 : 可以观察下连接信息:

总结 

纸上得来终觉浅,绝知此事要躬行,希望大家可以把理论配合上面的实例进行消化,搭好服务端也可以直接使用测试工具好好玩耍一波

更多编程相关知识,请访问:编程教学!!

以上是十分鐘快速了解websocket! !的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除