egg-socket 配置和使用


nodejs

Socket.IO

Socket.IO 是一個基於 Node.js 的實時應用程序框架,在即時通訊、通知與消息推送,實時分析等場景中有較為廣泛的應用。

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

開啟插件

// {app_root}/config/plugin.js
exports.io = {
  enable: true,
  package: 'egg-socket.io',
}; 

配置

// {app_root}/config/config.${env}.js
exports.io = {
  init: { }, // passed to engine.io
  namespace: {
    '/': {
      connectionMiddleware: [],
      packetMiddleware: [],   // 針對消息的處理暫時不實現
    },
  },
};

開啟 egg-socket.io 的項目目錄結構

chat
├── app
│   ├── extend
│   │   └── helper.js
│   ├── io
│   │   ├── controller
│   │   │   └── default.js
│   │   └── middleware
│   │       ├── connection.js
│   │       └── packet.js
│   └── router.js
├── config
└── package.json

注意:對應的文件都在 app/io 目錄下

Router 配置 (路由負責將 socket 連接的不同 events 分發到對應的 controller),不用controller方法可以暫時不用配置

// {app_root}/app/router.js

module.exports = app => {
  const { router, controller, io } = app;

  // default
  router.get('/', controller.home.index);

  // socket.io
  io.of('/').route('server', io.controller.home.server);
};

 egg-socket.io中間件負責 socket 連接的處理

// {app_root}/app/io/middleware/auth.js

const PREFIX = 'room';   //定義房間號

module.exports = () => {
  return async (ctx, next) => {
    const { app, socket, logger, helper } = ctx;
    const id = socket.id;
    const nsp = app.io.of('/');
    const query = socket.handshake.query;  //獲取socket鏈接傳過來的參數

    // 用戶信息
    const { room, userId } = query;
    const rooms = [ room ];

    logger.debug('#user_info', id, 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}`);

    logger.debug('#has_exist', hasRoom);

    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) => {
      logger.debug('#online_join', clients);

      // 更新在線用戶列表
      nsp.to(room).emit('online', {
        clients,
        action: 'join',
        target: 'participator',
        message: `User(${id}) joined.`,
      });
    });

    await next();

    // 用戶離開
    logger.debug('#leave', room);

    // 在線列表
    nsp.adapter.clients(rooms, (err, clients) => {
      logger.debug('#online_leave', clients);

      // 獲取 client 信息
      // const clientsDetail = {};
      // clients.forEach(client => {
      //   const _client = app.io.sockets.sockets[client];
      //   const _query = _client.handshake.query;
      //   clientsDetail[client] = _query;
      // });

      // 更新在線用戶列表
      nsp.to(room).emit('online', {
        clients,
        action: 'leave',
        target: 'participator',
        message: `User(${id}) leaved.`,
      });
    });

  };
};

 Controller 對客戶端發送的 event 進行處理;

// {app_root}/app/io/controller /nsp.js
'use strict';

const Controller = require('egg').Controller;

class NspController extends Controller {

}

module.exports = NspController;

 使用方法

async index(){
const nsp = this.app.io.of('/');
nsp.to('app1').emit("step",{數據});
}

 

 

vue

安裝 sockrt.io 和 調用

$ npm i socket.io-client –save
import io from 'socket.io-client'; 

vue.config.js配置

'/socket.io': {

  target: 'http://127.0.0.1:7001',

  changeOrigin: true,

  ws:true,

  pathRewrite: {
 
   '^/socket.io': '/socket.io'

  }

}

使用方法

//createIdSocket方法在mounted里面調用就可以
createIdSocket(){

  const socket = io.connect(location.origin, {

    transports: ['websocket'],  //傳輸方式為'websocket'
    query: {

      sessionId: 'app1'
    //app1為房間號
   }

  });

  socket.on("connect", () => {
 
  });

  socket.on("step", msg => {

    console.log('msg',msg); //返回數據的處理

  });
  //重新連接時,將transports選項重置為Websocket  
  socket.on('reconnect_attempt', () => {

    socket.io.opts.transports = ['polling', 'websocket'];

  });
}

 注:socket 數據通信通過房間號建立聯系確定獲取數據內容


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM