zoukankan      html  css  js  c++  java
  • egg-socket在egg中的使用

    WebSocket 的产生源于 Web 开发中日益增长的实时通信需求,对比基于 http 的轮询方式,它大大节省了网络带宽,同时也降低了服务器的性能消耗; socket.io 支持 websocket、polling 两种数据传输方式以兼容浏览器不支持 WebSocket 场景下的通信需求。
     
    框架提供了 egg-socket.io 插件,增加了以下开发规约:
    namespace: 通过配置的方式定义 namespace(命名空间)
    middleware: 对每一次 socket 连接的建立/断开、每一次消息/数据传递进行预处理
    controller: 响应 socket.io 的 event 事件
    router: 统一了 socket.io 的 event 与 框架路由的处理配置方式
     
    安装
    $ npm i egg-socket.io --save

     开启插件:config/plugin.js

    exports.io = {
      enable: true,
      package: 'egg-socket.io',
    };

     配置插件config/config.default.js  

    / 和 new2 属于不同的命名空间 即如果你有两个业务用到了socket,可以分别用不同的命名空间去管理,如果只用到一个写一个及可

    exports.io = {
      init: { }, // passed to engine.io
      namespace: {
        '/': {
          connectionMiddleware: [],
          packetMiddleware: [],
        },
        '/news': {
          connectionMiddleware: [],
          packetMiddleware: [],
        },
      },
    };

     routerio.js 路由可以分别为不同的命名空间配置路由

    of 来划分命名空间
    io.of('/').route('chat', io.controller.chat.index);
    io.of('/').route('message', io.controller.chat.message);
    io.of('/').route('user', io.controller.chat.online);
    
    io.of('/news').route('news', io.controller.news.index);

    在生产环境下Nginx 配置

    location / {
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $host;
      proxy_pass   http://127.0.0.1:7001;
    
      # http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_bind
      # proxy_bind       $remote_addr transparent;
    }
    开启 egg-socket.io 的项目目录结构如下:
    chat
    ├── app
    │   ├── extend
    │   │   └── helper.js
    │   ├── io
    │   │   ├── controller
    │   │   │   └── default.js
    │   │   └── middleware
    │   │       ├── connection.js
    │   │       └── packet.js
    │   └── router.js
    ├── config
    └── package.json

    对应的文件都在io下

     app/io

    配置socket的中间件在 app/io/middleware 下    新建auth.js

    在每一个客户端连接或者退出时发生作用,故而我们通常在这一步进行授权认证,对认证失败的客户端做出相应的处理

    /**
     * Created by bear on 2018/2/12.
     */
    const PREFIX = 'room';  //定义房间号
    
    module.exports = app => {
      return async (ctx, next) => {
        const { app, socket, logger, helper } = ctx;
        const id = socket.id;
        const nsp = app.io.of('/');
        const query = socket.handshake.query;
    
        // 用户信息
        const { room, userId } = query;  //获取socket链接传过来的参数
        const rooms = [ room ];
    
        console.log(room, userId);
    
        const tick = (id, msg) => {
          logger.debug('#tick', id, msg);
          // 踢出用户前发送消息
          socket.emit(id, helper.parseMsg('deny', msg));
          // 调用 adapter 方法踢出用户,客户端触发 disconnect 事件
          nsp.adapter.remoteDisconnect(id, true, err => {
            logger.error(err);
          });
        };
        // 检查房间是否存在,不存在则踢出用户
        // 备注:此处 app.redis 与插件无关,可用其他存储代替
       
        const hasRoom = await app.redis.get(`${PREFIX}:${room}`);
        console.log(hasRoom,`${PREFIX}:${room}`)
    
        // if (!hasRoom) {
        //   tick(id, {
        //     type: 'deleted',
        //     message: 'deleted, room has been deleted.',
        //   });
        //   return;
        // }
    
        // 用户加入
        logger.debug('#join', room);
        socket.join(room);
    
        // 在线列表
        nsp.adapter.clients(rooms, (err, clients) => {
          // 更新在线用户列表
          nsp.to(room).emit('online', {
            clients,
            action: 'join',
            target: 'participator',
            message: `User(${id}) joined.`,
          });
          console.log(123,clients)
        });
        // socket.emit('connect', 'packet received!');
        
        await next();
        console.log('disconnect!');
    
      };
    };

     app/io/middleware/filter.js

    module.exports = (app) => {
        return async (ctx, next) => {
            // console.log(ctx.packet);
            await next();
            // console.log('packet response!');
        };
    };
     
    踢出用户示例:
     
    const tick = (id, msg) => {
      logger.debug('#tick', id, msg);
      socket.emit(id, msg);
      app.io.of('/').adapter.remoteDisconnect(id, true, err => {
        logger.error(err);
      });
    };
    Controller
    Controller 对客户端发送的 event 进行处理;由于其继承于 egg.Contoller, 拥有如下成员对象:
    ctx
    app
    service
    config
    logger

    app/io/controller/chat.js

    /**
     * Created by bear on 2018/2/12.
     */
    module.exports = app => {
      class chatController extends app.Controller {
        async index() {
          this.ctx.socket.emit('res', 'test');
        }
        async message() {   //方法通过 客户端 this.emit('message',{})//触发
          this.ctx.socket.emit('message', 'test');
          const params = this.ctx.args[0];
         // this.ctx.service.message.sendPeerMessage(params);
          console.log(2,params);
        }
    
    
        async online() {// modelMessage.sendOfflineMessage(socket, data.userId);
        }
      }
      return chatController;
    };
  • 相关阅读:
    selenium之css选择器高级用法
    常系数线性齐次递推新理解
    关于莫队本质的理解
    2021.5.8总结
    决策单调性优化dp
    字符串 复习
    5.1总结
    树分块 学习笔记
    莫反 复习
    P4570 [BJWC2011]元素
  • 原文地址:https://www.cnblogs.com/kbnet/p/10949074.html
Copyright © 2011-2022 走看看