• websocket给指定客户端推送消息


    业务场景

    最近有一个业务场景是要做实时语音转义,考虑到实时性,所以决定采用websocket实现。

    业务场景是A客户端(手机)进行语音转义的结果实时同步到B客户端(pc),这就需要用到websocket将A转义的结果发送给服务端,服务端接收到A的信息直接同步推送给B,所以它就和简单的无差别广播不同了。

    看了网上的websocket示例,很少关于如何针对指定客户端推送消息的,解释的也是错误的。于是决定写一个大家拿去即用的示例。

    websocket的通信过程

    首先解释下面示例websocket服务的通信过程

    1.服务端起一个websocket的端口服务

    2.然后客户端去 new WebSocket(服务端地址,如:ws://127.0.0.1:5201/?userId=liubao),此时就走到了服务端的wss.on(‘connection’)建立一个一对一连接了。为了方便大家理解,我把userId直接放url里了(真实业务场景一般是从header里拿token解析用户是谁)

    3.服务端就把这个userId的请求连接池储存到clients数组里

    4.此时客户端发送一个消息给服务端,就走到了 ws.on(‘message’)里,我们用data去接收客户端发送的消息

    备注:从客户端接收到的数据是二进制的buffer信息(二进制信息是传统json信息速度的10倍+),所以在打印data时是个buffer,要想打印出来它的具体信息可以这样

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

    取data信息时必须先转成字符串,否则是buffer数组信息,无法处理。

    我们从客户端发送一个json信息包含userId和要发送的message

    example:

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

    5.有userId时遍历连接池,找到相同的userId连接池,进行推送消息

    最后效果

    在这里插入图片描述

    服务端代码

    copy下面代码到index.js文件,然后安装依赖和运行

    npm i ws
    node index.js
    
    • 1
    • 2
    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参数方法
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
  • 相关阅读:
    微电网优化调度(风、光、储能、柴油机)(Python代码实现)
    【必备】用VSCode开发Vue程序必备插件之一Vue Language Features (Volar)
    爬虫究竟是合法还是违法的?
    Java面向对象(上)
    wflow模型sbm
    如何在Win系统部署Tomcat服务并实现远程访问内网站点
    C# 语言的面向对象技术
    Sklearn逻辑回归
    计算机网络的OSI七层模型
    智能城市环境中的医疗物联网:基于量子同态加密的医疗成像架构(Idea)
  • 原文地址:https://blog.csdn.net/sinat_15955423/article/details/127949531