node.js中如何使用socket.io實(shí)現(xiàn)一個(gè)實(shí)時(shí)通訊應(yīng)用

今天小編給大家分享一下node.js中如何使用socket.io實(shí)現(xiàn)一個(gè)實(shí)時(shí)通訊應(yīng)用的相關(guān)知識(shí)點(diǎn),內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識(shí),所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來(lái)了解一下吧。

成都創(chuàng)新互聯(lián)公司是一家專(zhuān)注于成都網(wǎng)站建設(shè)、網(wǎng)站建設(shè)與策劃設(shè)計(jì),建平網(wǎng)站建設(shè)哪家好?成都創(chuàng)新互聯(lián)公司做網(wǎng)站,專(zhuān)注于網(wǎng)站建設(shè)十余年,網(wǎng)設(shè)計(jì)領(lǐng)域的專(zhuān)業(yè)建站公司;建站業(yè)務(wù)涵蓋:建平等地區(qū)。建平做網(wǎng)站價(jià)格咨詢(xún):18980820575

WebSocket概念

不同于HTTP半雙工協(xié)議,WebSocket是基于TCP 連接的全雙工協(xié)議,支持客戶(hù)端服務(wù)端雙向通信。

WebSocket使得客戶(hù)端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡(jiǎn)單,允許服務(wù)端主動(dòng)向客戶(hù)端推送數(shù)據(jù)。在 WebSocket API 中,瀏覽器和服務(wù)器只需要完成一次握手,兩者之間就直接可以創(chuàng)建持久性的連接,并進(jìn)行雙向數(shù)據(jù)傳輸。

WebSocket API中,瀏覽器和服務(wù)器只需要做一個(gè)握手的動(dòng)作,然后,瀏覽器和服務(wù)器之間就形成了一條快速通道。兩者之間就直接可以數(shù)據(jù)互相傳送。

node.js中如何使用socket.io實(shí)現(xiàn)一個(gè)實(shí)時(shí)通訊應(yīng)用

實(shí)現(xiàn)

原生實(shí)現(xiàn)

WebSocket對(duì)象一共支持四個(gè)消息 onopen, onmessage, onclose和onerror。

建立連接

通過(guò)javascript可以快速的建立一個(gè)WebSocket連接:

var Socket = new WebSocket(url, [protocol] );

以上代碼中的第一個(gè)參數(shù)url, 指定連接的URL。第二個(gè)參數(shù) protocol是可選的,指定了可接受的子協(xié)議。

同http協(xié)議使用http://開(kāi)頭一樣,WebSocket協(xié)議的URL使用ws://開(kāi)頭,另外安全的WebSocket協(xié)議使用wss://開(kāi)頭。

當(dāng)Browser和WebSocketServer連接成功后,會(huì)觸發(fā)onopen消息。

Socket.onopen = function(evt) {};

如果連接失敗,發(fā)送、接收數(shù)據(jù)失敗或者處理數(shù)據(jù)出現(xiàn)錯(cuò)誤,browser會(huì)觸發(fā)onerror消息。

Socket.onerror = function(evt) { };

當(dāng)Browser接收到WebSocketServer端發(fā)送的關(guān)閉連接請(qǐng)求時(shí),就會(huì)觸發(fā)onclose消息。

Socket.onclose = function(evt) { };

收發(fā)消息

當(dāng)Browser接收到WebSocketServer發(fā)送過(guò)來(lái)的數(shù)據(jù)時(shí),就會(huì)觸發(fā)onmessage消息,參數(shù)evt中包含server傳輸過(guò)來(lái)的數(shù)據(jù)。

Socket.onmessage = function(evt) { };

send用于向服務(wù)端發(fā)送消息。

Socket.send();

socket

WebSocket是跟隨HTML5一同提出的,所以在兼容性上存在問(wèn)題,這時(shí)一個(gè)非常好用的庫(kù)就登場(chǎng)了——Socket.io。

socket.io封裝了websocket,同時(shí)包含了其它的連接方式,你在任何瀏覽器里都可以使用socket.io來(lái)建立異步的連接。socket.io包含了服務(wù)端和客戶(hù)端的庫(kù),如果在瀏覽器中使用了socket.io的js,服務(wù)端也必須同樣適用。

socket.io是基于 Websocket 的Client-Server 實(shí)時(shí)通信庫(kù)。

socket.io底層是基于engine.io這個(gè)庫(kù)。engine.io為 socket.io 提供跨瀏覽器/跨設(shè)備的雙向通信的底層庫(kù)。engine.io使用了 Websocket 和 XHR 方式封裝了一套 socket 協(xié)議。在低版本的瀏覽器中,不支持Websocket,為了兼容使用長(zhǎng)輪詢(xún)(polling)替代。

API文檔

Socket.io允許你觸發(fā)或響應(yīng)自定義的事件,除了connect,message,disconnect這些事件的名字不能使用之外,你可以觸發(fā)任何自定義的事件名稱(chēng)。

建立連接

  const socket = io("ws://0.0.0.0:port"); // port為自己定義的端口號(hào)
  let io = require("socket.io")(http);
  io.on("connection", function(socket) {})

消息收發(fā)

一、發(fā)送數(shù)據(jù)

socket.emit(自定義發(fā)送的字段, data);

二、接收數(shù)據(jù)

 socket.on(自定義發(fā)送的字段, function(data) {
    console.log(data);
  })

斷開(kāi)連接

一、全部斷開(kāi)連接

  let io = require("socket.io")(http);
  io.close();

二、某個(gè)客戶(hù)端斷開(kāi)與服務(wù)端的鏈接

  // 客戶(hù)端
  socket.emit("close", {});
 // 服務(wù)端
  socket.on("close", data => {
    socket.disconnect(true);
  });

room和namespace

有時(shí)候websocket有如下的使用場(chǎng)景:1.服務(wù)端發(fā)送的消息有分類(lèi),不同的客戶(hù)端需要接收的分類(lèi)不同;2.服務(wù)端并不需要對(duì)所有的客戶(hù)端都發(fā)送消息,只需要針對(duì)某個(gè)特定群體發(fā)送消息;

針對(duì)這種使用場(chǎng)景,socket中非常實(shí)用的namespace和room就上場(chǎng)了。

先來(lái)一張圖看看namespace與room之間的關(guān)系:

node.js中如何使用socket.io實(shí)現(xiàn)一個(gè)實(shí)時(shí)通訊應(yīng)用

namespace

服務(wù)端

  io.of("/post").on("connection", function(socket) {
    socket.emit("new message", { mess: `這是post的命名空間` });
  });
  
  io.of("/get").on("connection", function(socket) {
    socket.emit("new message", { mess: `這是get的命名空間` });
  });

客戶(hù)端

  // index.js
  const socket = io("ws://0.0.0.0:****/post");
  socket.on("new message", function(data) {
    console.log('index',data);
  }
  
  //message.js
  const socket = io("ws://0.0.0.0:****/get");
  socket.on("new message", function(data) {
    console.log('message',data);
  }

room

客戶(hù)端

 //可用于客戶(hù)端進(jìn)入房間;
  socket.join('room one');
  //用于離開(kāi)房間;
  socket.leave('room one');

服務(wù)端

  io.sockets.on('connection',function(socket){
    //提交者會(huì)被排除在外(即不會(huì)收到消息)
    socket.broadcast.to('room one').emit('new messages', data);
    // 向所有用戶(hù)發(fā)送消息
    io.sockets.to(data).emit("recive message", "hello,房間中的用戶(hù)");   
  }

用socket.io實(shí)現(xiàn)一個(gè)實(shí)時(shí)接收信息的例子

終于來(lái)到應(yīng)用的階段啦,服務(wù)端用node.js模擬了服務(wù)端接口。以下的例子都在本地服務(wù)器中實(shí)現(xiàn)。

服務(wù)端

先來(lái)看看服務(wù)端,先來(lái)開(kāi)啟一個(gè)服務(wù),安裝expresssocket.io

安裝依賴(lài)

npm install --Dev express
npm install --Dev socket.io

構(gòu)建node服務(wù)器

 let app = require("express")();
  let http = require("http").createServer(handler);
  let io = require("socket.io")(http);
  let fs = require("fs");
  
  http.listen(port); //port:輸入需要的端口號(hào)
  
  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);
    res.end(data);
   });
  }
  
  io.on("connection", function(socket) {
    console.log('連接成功');
    //連接成功之后發(fā)送消息
    socket.emit("new message", { mess: `初始消息` });
    
  });

客戶(hù)端

核心代碼——index.html(向服務(wù)端發(fā)送數(shù)據(jù))

 <div>發(fā)送信息</div>
  <input placeholder="請(qǐng)輸入要發(fā)送的信息" />
  <button onclick="postMessage()">發(fā)送</button>
 // 接收到服務(wù)端傳來(lái)的name匹配的消息
  socket.on("new message", function(data) {
   console.log(data);
  });
  
  function postMessage() {
   socket.emit("recive message", {
    message: content,
    time: new Date()
   });
   messList.push({
    message: content,
    time: new Date()
   });
  }

核心代碼——message.html(從服務(wù)端接收數(shù)據(jù))

socket.on("new message", function(data) {
   console.log(data);
  });

效果

實(shí)時(shí)通訊效果

node.js中如何使用socket.io實(shí)現(xiàn)一個(gè)實(shí)時(shí)通訊應(yīng)用

客戶(hù)端全部斷開(kāi)連接

node.js中如何使用socket.io實(shí)現(xiàn)一個(gè)實(shí)時(shí)通訊應(yīng)用

某客戶(hù)端斷開(kāi)連接

node.js中如何使用socket.io實(shí)現(xiàn)一個(gè)實(shí)時(shí)通訊應(yīng)用

namespace應(yīng)用

node.js中如何使用socket.io實(shí)現(xiàn)一個(gè)實(shí)時(shí)通訊應(yīng)用

加入房間

node.js中如何使用socket.io實(shí)現(xiàn)一個(gè)實(shí)時(shí)通訊應(yīng)用

離開(kāi)房間

node.js中如何使用socket.io實(shí)現(xiàn)一個(gè)實(shí)時(shí)通訊應(yīng)用

框架中的應(yīng)用

npm install socket.io-client
const socket = require('socket.io-client')('http://localhost:port');

  componentDidMount() {
    socket.on('login', (data) => {
      console.log(data)
    });
    socket.on('add user', (data) => {
      console.log(data)
    });
    socket.on('new message', (data) => {
      console.log(data)
    });
  }

分析webSocket協(xié)議

Headers

node.js中如何使用socket.io實(shí)現(xiàn)一個(gè)實(shí)時(shí)通訊應(yīng)用

請(qǐng)求包

 Accept-Encoding: gzip, deflate
  Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
  Cache-Control: no-cache
  Connection: Upgrade
  Cookie: MEIQIA_VISIT_ID=1IcBRlE1mZhdVi1dEFNtGNAfjyG; token=0b81ffd758ea4a33e7724d9c67efbb26; io=ouI5Vqe7_WnIHlKnAAAG
  Host: 0.0.0.0:2699
  Origin: http://127.0.0.1:5500
  Pragma: no-cache
  Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
  Sec-WebSocket-Key: PJS0iPLxrL0ueNPoAFUSiA==
  Sec-WebSocket-Version: 13
  Upgrade: websocket
  User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1

請(qǐng)求包說(shuō)明:

  • 必須是有效的http request 格式;

  • HTTP request method 必須是GET,協(xié)議應(yīng)不小于1.1 如: Get / HTTP/1.1;

  • 必須包括Upgrade頭域,并且其值為“websocket”,用于告訴服務(wù)器此連接需要升級(jí)到websocket;

  • 必須包括”Connection” 頭域,并且其值為“Upgrade”;

  • 必須包括”Sec-WebSocket-Key”頭域,其值采用base64編碼的隨機(jī)16字節(jié)長(zhǎng)的字符序列;

  • 如果請(qǐng)求來(lái)自瀏覽器客戶(hù)端,還必須包括Origin頭域 。 該頭域用于防止未授權(quán)的跨域腳本攻擊,服務(wù)器可以從Origin決定是否接受該WebSocket連接;

  • 必須包括“Sec-webSocket-Version”頭域,是當(dāng)前使用協(xié)議的版本號(hào),當(dāng)前值必須是13;

  • 可能包括“Sec-WebSocket-Protocol”,表示client(應(yīng)用程序)支持的協(xié)議列表,server選擇一個(gè)或者沒(méi)有可接受的協(xié)議響應(yīng)之;

  • 可能包括“Sec-WebSocket-Extensions”, 協(xié)議擴(kuò)展, 某類(lèi)協(xié)議可能支持多個(gè)擴(kuò)展,通過(guò)它可以實(shí)現(xiàn)協(xié)議增強(qiáng);

  • 可能包括任意其他域,如cookie.

應(yīng)答包

應(yīng)答包說(shuō)明:

 Connection: Upgrade
  Sec-WebSocket-Accept: I4jyFwm0r1J8lrnD3yN+EvxTABQ=
  Sec-WebSocket-Extensions: permessage-deflate
  Upgrade: websocket
  • 必須包括Upgrade頭域,并且其值為“websocket”;

  • 必須包括Connection頭域,并且其值為“Upgrade”;

  • 必須包括Sec-WebSocket-Accept頭域,其值是將請(qǐng)求包“Sec-WebSocket-Key”的值,與”258EAFA5-E914-47DA-95CA-C5AB0DC85B11″這個(gè)字符串進(jìn)行拼接,然后對(duì)拼接后的字符串進(jìn)行sha-1運(yùn)算,再進(jìn)行base64編碼,就是“Sec-WebSocket-Accept”的值;

  • 應(yīng)答包中冒號(hào)后面有一個(gè)空格;

  • 最后需要兩個(gè)空行作為應(yīng)答包結(jié)束。

請(qǐng)求數(shù)據(jù)

 EIO: 3
  transport: websocket
  sid: 8Uehk2UumXoHVJRzAAAA
  • EIO:3 表示使用的是engine.io協(xié)議版本3

  • transport 表示傳輸采用的類(lèi)型

  • sid: session id (String)

Frames

WebSocket協(xié)議使用幀(Frame)收發(fā)數(shù)據(jù),在控制臺(tái)->Frames中可以查看發(fā)送的幀數(shù)據(jù)。

其中幀數(shù)據(jù)前的數(shù)字代表什么意思呢?

這是 Engine.io協(xié)議,其中的數(shù)字是數(shù)據(jù)包編碼:

<Packet type id> [<data>]

0 open——在打開(kāi)新傳輸時(shí)從服務(wù)器發(fā)送(重新檢查)

1 close——請(qǐng)求關(guān)閉此傳輸,但不關(guān)閉連接本身。

2 ping——由客戶(hù)端發(fā)送。服務(wù)器應(yīng)該用包含相同數(shù)據(jù)的乓包應(yīng)答

客戶(hù)端發(fā)送:2probe探測(cè)幀

3 pong——由服務(wù)器發(fā)送以響應(yīng)ping數(shù)據(jù)包。

服務(wù)器發(fā)送:3probe,響應(yīng)客戶(hù)端

4 message——實(shí)際消息,客戶(hù)端和服務(wù)器應(yīng)該使用數(shù)據(jù)調(diào)用它們的回調(diào)。

5 upgrade——在engine.io切換傳輸之前,它測(cè)試,如果服務(wù)器和客戶(hù)端可以通過(guò)這個(gè)傳輸進(jìn)行通信。如果此測(cè)試成功,客戶(hù)端發(fā)送升級(jí)數(shù)據(jù)包,請(qǐng)求服務(wù)器刷新其在舊傳輸上的緩存并切換到新傳輸。

6 noop——noop數(shù)據(jù)包。主要用于在接收到傳入WebSocket連接時(shí)強(qiáng)制輪詢(xún)周期。

實(shí)例

node.js中如何使用socket.io實(shí)現(xiàn)一個(gè)實(shí)時(shí)通訊應(yīng)用

node.js中如何使用socket.io實(shí)現(xiàn)一個(gè)實(shí)時(shí)通訊應(yīng)用

以上的截圖是上述例子中數(shù)據(jù)傳輸?shù)膶?shí)例,分析一下大概過(guò)程就是:

  • connect握手成功

  • 客戶(hù)端會(huì)發(fā)送2 probe探測(cè)幀

  • 服務(wù)端發(fā)送響應(yīng)幀3probe

  • 客戶(hù)端會(huì)發(fā)送內(nèi)容為5的Upgrade幀

  • 服務(wù)端回應(yīng)內(nèi)容為6的noop幀

  • 探測(cè)幀檢查通過(guò)后,客戶(hù)端停止輪詢(xún)請(qǐng)求,將傳輸通道轉(zhuǎn)到websocket連接,轉(zhuǎn)到websocket后,接下來(lái)就開(kāi)始定期(默認(rèn)是25秒)的 ping/pong

  • 客戶(hù)端、服務(wù)端收發(fā)數(shù)據(jù),4表示的是engine.io的message消息,后面跟隨收發(fā)的消息內(nèi)容

為了知道Client和Server鏈接是否正常,項(xiàng)目中使用的ClientSocket和ServerSocket都有一個(gè)心跳的線程,這個(gè)線程主要是為了檢測(cè)Client和Server是否正常鏈接,Client和Server是否正常鏈接主要是用ping pong流程來(lái)保證的。

該心跳定期發(fā)送的間隔是socket.io默認(rèn)設(shè)定的25m,在上圖中也可觀察發(fā)現(xiàn)。該間隔可通過(guò)配置修改。

node.js中如何使用socket.io實(shí)現(xiàn)一個(gè)實(shí)時(shí)通訊應(yīng)用

以上就是“node.js中如何使用socket.io實(shí)現(xiàn)一個(gè)實(shí)時(shí)通訊應(yīng)用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會(huì)為大家更新不同的知識(shí),如果還想學(xué)習(xí)更多的知識(shí),請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

網(wǎng)站標(biāo)題:node.js中如何使用socket.io實(shí)現(xiàn)一個(gè)實(shí)時(shí)通訊應(yīng)用
文章地址:http://bm7419.com/article30/pcogpo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)建站、ChatGPT虛擬主機(jī)、網(wǎng)站改版營(yíng)銷(xiāo)型網(wǎng)站建設(shè)、電子商務(wù)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

綿陽(yáng)服務(wù)器托管