Websocket は指定されたクライアントにメッセージをプッシュします

ビジネスシーン

最近、リアルタイムで音声エスケープを行うビジネスシナリオがあり、リアルタイム性を考慮してWebSocketを使用して実現することにしました。

ビジネス シナリオは、クライアント A (携帯電話) の音声エスケープ結果がクライアント B (PC) にリアルタイムで同期されるというものです。これには、WebSocket を使用して A のエスケープ結果をサーバーに送信する必要があり、サーバーは A の音声エスケープ結果を受信します。情報を直接Bに同期してPushするため、単純な無差別放送とは異なります。

インターネット上の WebSocket の例を読んだところ、特定のクライアントにメッセージをプッシュする方法についての説明はほとんどなく、説明も間違っています。そこで、誰でもすぐに使える例を書くことにしました。

WebSocketの通信プロセス

まず、次の例の WebSocket サービスの通信プロセスを説明します

1. サーバーは WebSocket ポート サービスを開始します

2. 次に、クライアントは新しい WebSocket (サーバー アドレス、ws://127.0.0.1:5201/?userId=liubao など) に移動し、サーバーの wss.on('connection') に移動して接続を確立します。ペア 1 つが接続されています。全員が理解しやすいように、userId を URL に直接入力しました (実際のビジネス シナリオでは、通常、ヘッダーのトークンを使用してユーザーが誰であるかを分析します)。

3. サーバーは、この userId のリクエスト接続プールをクライアント配列に保存します。

4. この時点で、クライアントはサーバーにメッセージを送信し、それは ws.on('message') に進み、そこでデータを使用してクライアントから送信されたメッセージを受信します。

備考: クライアントから受信したデータはバイナリバッファ情報(バイナリ情報は従来のjson情報に比べて10倍高速)なので、データを印刷する際のバッファになります。

console.log('%s',data);

データ情報を取得する場合は、まず文字列に変換する必要があります。変換しないとバッファ配列情報となり、処理できません。

userId と送信するメッセージを含む json メッセージをクライアントから送信します。

例:

// 客户端A
{
    
     "userId": "liubao", "message": "给liubao一个小爱心" }
// 客户端B
{
    
     "userId": "bob", "message": "给你bob一个大铁锤" }

5. userId がある場合は接続プールを走査し、同じ userId 接続プールを見つけてメッセージをプッシュします。

最終効果

ここに画像の説明を挿入

サーバーコード

次のコードをindex.jsファイルにコピーし、依存関係をインストールして実行します。

npm i ws
node index.js
import {
    
     WebSocketServer } from 'ws';

const clients = []; // 与客户端建立的连接池

const wss = new WebSocketServer({
    
     port: 5201 }); // 创建一个websocket服务
wss.on('connection', function connection(ws, request, client) {
    
    
  let url = request.headers.origin + request.url; // example:ws://127.0.0.1:5201/?userId=liubao
  let userId = getParam(url, 'userId');
  if (userId) {
    
    
    clients.push({
    
     userId, ws: ws }); // 连接时只要url带userId参数,直接往客户端数组里塞入连接池信息
  }
  ws.on('message', function message(data, isBinary) {
    
     // 得到客户端往服务端发送的消息
    try {
    
    
      let objMessage = JSON.parse(`${
      
      data}`); // example:{ 'userId': 'liubao', 'message': '给你一个小爱心' }
      let {
    
     userId, message } = objMessage;
      let count = 0; // 发送客户端数量
      if (userId) {
    
    
        clients.forEach(e => {
    
    
          if (e['userId'] === userId) {
    
    
            count++;
            e['ws'].send(`${
      
      message}`);
          }
        });
        ws.send(`已发送userId为${
      
      userId}${
      
      count}个客户端`);
      } else {
    
    
        ws.send(JSON.stringify({
    
     error: '请发送指定userId的客户端' }));
      }
    } catch (err) {
    
    
      ws.send(JSON.stringify({
    
     error: err.message }));
    }
  });
  ws.on('close', function close(event) {
    
    
    console.log('关闭了');
  });
});

const getParam = (url, param) => new URLSearchParams(new URL(url).search).get(param); // es6获取URL参数方法

おすすめ

転載: blog.csdn.net/sinat_15955423/article/details/127949531