049关于Socket.IO的功能预研与示例解析

049关于Socket.IO的功能预研与示例解析

什么是Socket.IO

Socket.IO是一个库,可用于在浏览器和服务器之间进行实时,双向和基于事件的通信。

主要特点

可靠性

即使存在以下情况,也会建立连接:

  • 代理
  • 负载处理方案
  • 个人防火墙和防病毒软件

因为,它依赖于Engine.IO,该引擎首先建立长轮询连接,然后尝试升级到更好的传输,例如WebSocket。

自动重新连接支持

除非另有指示,否则断开连接的客户端将尝试永久重新连接,直到服务器再次可用为止。

断线检测

心跳机制使服务器和客户端都可以知道对方何时不再响应。

通过在服务器和客户端上设置计时器,并在连接握手期间共享超时值(pingInterval和pingTimeout)实现。

二进制支持

可以发出任何可序列化的数据结构,包括:

  • 浏览器中的ArrayBuffer和Blob
  • Node.js中的ArrayBuffer和Buffer

JSON支持

自带JSON处理,服务器和客户端均无须特殊处理,直接使用JSON数据。

多路传输支持

为了在应用程序内创建关注点分离(例如,每个模块或基于权限),Socket.IO允许您创建多个Namespaces,它们将充当单独的通信通道,共享相同的基础连接。

服务器端
var io = require('socket.io')(80);
var chat = io
  .of('/chat')
  .on('connection', function (socket) {
    socket.emit('a message', {
        that: 'only'
      , '/chat': 'will get'
    });
    chat.emit('a message', {
        everyone: 'in'
      , '/chat': 'will get'
    });
  });

var news = io
  .of('/news')
  .on('connection', function (socket) {
    socket.emit('item', { news: 'item' });
  });
客户端
  var chat = io.connect('http://localhost/chat')
    , news = io.connect('http://localhost/news');
  
  chat.on('connect', function () {
    chat.emit('hi!');
  });
  
  news.on('news', function () {
    news.emit('woot');
  });

客房支援

在每个Namespace中,您可以定义套接字可以加入和离开的任意通道,称为Rooms。然后,您可以广播到任何给定的房间,到达已加入该房间的每个插槽。

这是有用的功能,用于向一组用户或连接到多个设备的给定用户发送通知。

const orderNamespace = io.of("/orders");

orderNamespace.on("connection", (socket) => {
  socket.join("room1");
  orderNamespace.to("room1").emit("hello");
});

const userNamespace = io.of("/users");

userNamespace.on("connection", (socket) => {
  socket.join("room1");
  userNamespace.to("room1").emit("holà");
});

使用Socket.IO须知

Socket.IO 不是 WebSocket实现(在可能的情况下使用WebSocket作为传输工具)。

这就是为什么WebSocket客户端将无法成功连接到Socket.IO服务器,而Socket.IO客户端也将无法连接到WebSocket服务器的原因。

安装

js服务器端

npm install --save socket.io

js客户端

npm install --save socket.io-client

其他客户端实施

Java:https://github.com/socketio/socket.io-client-java
C ++:https://github.com/socketio/socket.io-client-cpp
swift:https://github.com/socketio/socket.io-client-swift
dart:https://github.com/rikulo/socket.io-client-dart
Python:https://github.com/miguelgrinberg/python-socketio
.Net:https://github.com/Quobject/SocketIoClientDotNet

与Node http服务器一起使用

服务器(app.js)

var app = require('http').createServer(handler)
var io = require('socket.io')(app);
var fs = require('fs');

app.listen(80);

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) {
  socket.emit('news', { hello: 'world' });
  socket.on('my other event', function (data) {
    console.log(data);
  });
});  

客户端(index.html)

<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io('http://localhost');
  socket.on('news', function (data) {
    console.log(data);
    socket.emit('my other event', { my: 'data' });
  });
</script>

与Express一起使用

服务器(app.js)

var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);

server.listen(80);
// WARNING: app.listen(80) will NOT work here!

app.get('/', function (req, res) {
  res.sendFile(__dirname + '/index.html');
});

io.on('connection', function (socket) {
  socket.emit('news', { hello: 'world' });
  socket.on('my other event', function (data) {
    console.log(data);
  });
});

客户端(index.html)

<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost');
  socket.on('news', function (data) {
    console.log(data);
    socket.emit('my other event', { my: 'data' });
  });
</script>

发送易失性消息

有时可能会丢弃某些消息。假设您有一个应用程序可显示关键字的实时推文bieber。

如果某个客户端尚未准备好接收消息(由于网络速度慢或其他问题,或者由于它们是通过长时间轮询连接的,并且处于请求-响应周期的中间),则它没有接收到所有推文与bieber相关,您的应用程序不会受到影响。

在这种情况下,您可能希望将这些消息作为易失性消息发送。

服务器

var io = require('socket.io')(80);

io.on('connection', function (socket) {
  // 处理防抖用
  var tweets = setInterval(function () {
    getBieberTweet(function (tweet) {
      socket.volatile.emit('bieber tweet', tweet);
    });
  }, 100);

  socket.on('disconnect', function () {
    clearInterval(tweets);
  });
});

发送和获取数据(确认)

有时,当客户端确认消息接收后,您可能希望获得回调。

为此,只需将函数作为.send或.emit的最后一个参数传递即可。

而且,当您使用时.emit,确认是由您完成的,这意味着您还可以传递数据:

服务器

var io = require('socket.io')(80);

io.on('connection', function (socket) {
  socket.on('ferret', function (name, word, fn) {
    fn(name + ' says ' + word);
  });
});

客户端

  var socket = io(); // TIP: io() with no args does auto-discovery
  socket.on('connect', function () { // TIP: you can avoid listening on `connect` and listen on events directly too!
    socket.emit('ferret', 'tobi', 'woot', function (data) { // args are sent in order to acknowledgement function
      console.log(data); // data will be 'tobi says woot'
    });
  });

广播消息

要广播,只需broadcast在emit和send方法调用中添加一个标志。广播意味着将消息发送到其他人(除了自己)。

服务器

var io = require('socket.io')(80);

io.on('connection', function (socket) {
  socket.broadcast.emit('user connected');
});

像跨浏览器的WebSocket一样使用它,如果只需要WebSocket语义,也可以这样做。只需利用send并收听message事件:

服务器(app.js)

var io = require('socket.io')(80);

io.on('connection', function (socket) {
  socket.on('message', function () { });
  socket.on('disconnect', function () { });
});

客户端(index.html)

<script>
  var socket = io('http://localhost/');
  socket.on('connect', function () {
    socket.send('hi');

    socket.on('message', function (msg) {
      // my msg
    });
  });
</script>

web-dev\web-server\src\utils\Ws\Index.ts

module.exports = (Server: any) => {
  // 实例 = 业务代码
  const serverWs: any = require('../../server/ws/index');

  // 引入ws服务
  const Socket = require('socket.io');

  // 基于http的Server,建立WebSocket服务
  const ws = Socket(Server, {
    // 配置相关参数详解:https://socket.io/docs/v4/server-options/
    path: '/wsiot', // path (字符串):捕获webSocket连接的路径名,默认为(/socket.io)。
    cors: {
      origin: '*', // 支持单个网址,或网址的数组
      methods: ['GET', 'POST', 'PUT'], // 请求方式
    },
    /**
    cors:true, // 开放跨域
    allowEIO3: true, // 是否启用与V2版本的客户端兼容,默认是false
    serveClient: false, // serverClient (布尔型):是否为本地文件提供服务,默认为(true)。
    cookie: false,
    pingInterval: 10000,// pingTimeout (数值型):客户端在没有收到服务器端的响应时,等待多少毫秒数,,默认是60000毫秒(即1分钟)。
    pingTimeout: 5000,// pingInterval (数值型):服务器端在发送响应包前延迟多少毫秒,默认为25000毫秒(即25秒)。
    transports: ['polling', 'websocket'], //transports (Array包含一系列字符串元素的数组):这一选项规定了允许哪些连接方式,默认的(['polling','websocket']),强制使用websocket可以这样['websocket']配置。
    origins:'*',// origins (字符串):规定被允许的域,默认为(*) 。
    adapter:{},// adapter (Adapter对象):使用哪一个适配器对象,默认的指向Adapter类的一个实例,详情跳转至socket.io-adapter
    parser:{},// parser (Parser对象):指向一个parser对象,默认使用与socket.io相关联的socket.io-parser
    */
  });

  // 封装下游模型数据框架
  const wsModel: any = {
    ws,
    nsp: {},
    config: {},
  };

  // 执行ws服务
  serverWs(wsModel);
};

web-dev\web-server\src\utils\Ws\Ws.ts

module.exports = (
  wsModel: any = {},
  nsp: string = '',
  socketModel: any = {}
) => {
  // 当前命名空间的ws服务
  function wsNspServer(pnsp: string = nsp) {
    return wsModel.nsp[pnsp].ws;
  }
  // 当前命名空间的model数据
  function wsNspModel(pnsp: string = nsp) {
    return wsModel.nsp[pnsp].model;
  }
  // 初始化连接
  function wsConnect(fn: any, pnsp: string = nsp) {
    wsNspServer(pnsp).on('connection', fn);
  }
  // 接收连接发来的消息
  function socketQuery() {
    return socketModel.socket.handshake.query;
  }
  // 当前连接的id
  function socketId() {
    return socketModel.socket.id;
  }
  // 接收连接发来的消息
  function wsOn(id: string, fn: any) {
    socketModel.socket.on(id, fn);
  }
  // 对当前连接发送消息
  function wsEmit(id: string, data: any, callback: any = null) {
    if (callback) {
      socketModel.socket.emit(id, data, callback);
    } else {
      socketModel.socket.emit(id, data);
    }
  }
  // 发送data到指定用户id那里
  function wsEmitTo(
    userid: string,
    id: string,
    data: any,
    callback: any = null
  ) {
    const userSocket: any = getSocket(userid);
    if (callback) {
      // wsNspServer().to(getSocketId(userid)).emit(id, data, callback); // 另一种方案
      userSocket && userSocket.emit(id, data, callback);
    } else {
      userSocket && userSocket.emit(id, data);
    }
  }
  // 连接用户对外广播消息(用户自己不接收)
  function wsEmitBroadcast(id: string, data: any) {
    socketModel.socket.broadcast.emit(id, data);
  }
  // 广播消息
  function wsBroadcast(id: string, data: any, pnsp: string = nsp) {
    if (pnsp === 'all') {
      // 像所有空间发送消息
      Object.keys(wsModel.nsp).forEach((el: string) => {
        wsModel.nsp[el].ws.emit(id, data);
      });
    } else {
      wsNspServer(pnsp).emit(id, data);
    }
  }
  // 关闭当前或某个ID的连接
  function wsClose(userid: string = '') {
    if (userid) {
      const userSocket: any = getSocket(userid);
      userSocket && userSocket.disconnect(true);
    } else {
      socketModel.socket.disconnect(true);
    }
  }
  // 当连接用户离开(断开连接)的时候
  function wsDisconnect(fn: any) {
    wsOn('disconnect', fn);
  }
  // 获取在线用户的连接socket
  function getSocket(userid: string) {
    const userSocketId: any = getSocketId(userid);
    if (userSocketId) {
      return socketModel.socket.nsp.sockets.get(userSocketId);
    } else {
      return null;
    }
  }
  // 获取在线用户的连接id
  function getSocketId(userid: string) {
    return wsNspModel().user.connect.online.find(
      (el: any) => el.data.id === userid
    )?.id;
  }
  return {
    wsNspServer,
    wsNspModel,
    wsConnect,
    socketQuery,
    socketId,
    wsOn,
    wsEmit,
    wsEmitBroadcast,
    wsBroadcast,
    wsEmitTo,
    wsClose,
    wsDisconnect,
    getSocket,
    getSocketId,
  };
};

web-dev\web-server\src\server\ws\index.ts

const wsConfig: any = require('./config.json');

module.exports = (wsModel: any) => {
  // 加载ws配置
  wsModel.config = wsConfig;

  Object.keys(wsModel.config.nsp).forEach((nsp: any) => {
    wsModel.nsp[nsp] = { ws: {}, model: { broadcast: {}, user: {} } };
    // 注册命名空间
    if (nsp !== 'index') {
      wsModel.nsp[nsp].ws = wsModel.ws.of('/' + nsp);
    } else {
      wsModel.nsp[nsp].ws = wsModel.ws;
    }

    // 对公广播
    wsModel.config.nsp[nsp].broadcast.forEach((elb: string) => {
      // 注册broadcastModel
      wsModel.nsp[nsp].model.broadcast[elb] =
        require(`./${nsp}/broadcast/${elb}/Model.ts`)();
      // 注册broadcast服务
      require(`./${nsp}/broadcast/${elb}/Index.ts`)(wsModel, nsp);
    });

    wsModel.config.nsp[nsp].user.forEach((elu: string) => {
      // 注册userModel
      wsModel.nsp[nsp].model.user[elu] =
        require(`./${nsp}/user/${elu}/Model.ts`)();
    });

    const { wsConnect } = require('../../utils/Ws/Ws')(wsModel, nsp);

    // 监听到有用户连接上来了!
    wsConnect((socket: any) => {
      const socketModel: any = { socket };
      wsModel.config.nsp[nsp].user.forEach((elu: string) => {
        // 注册user服务
        require(`./${nsp}/user/${elu}/Index.ts`)(wsModel, nsp, socketModel);
      });
    });
  });

  // 当服务器断掉WS服务的时候
  wsModel.ws.on('disconnect', () => {
    console.log(666.306, 'disconnect');
  });
};

web-dev\web-server\src\server\ws\config.json

{
  "nsp": {
    "index": {
      "user": ["connect"],
      "broadcast": ["count"]
    },
    "online": {
      "user": ["connect"],
      "broadcast": ["count"]
    }
  }
}

web-dev\web-server\src\server\ws\online\user\connect\Index.ts

module.exports = (wsModel: any, nsp: string = '', socketModel: any) => {
  const {
    wsNspModel,
    socketQuery,
    socketId,
    wsOn,
    wsEmit,
    wsBroadcast,
    wsEmitTo,
    wsClose,
    wsDisconnect,
  } = require('../../../../../utils/Ws/Ws')(wsModel, nsp, socketModel);

  // 当连接用户离开(断开连接)的时候
  wsDisconnect((reason: any) => {
    // 如果是服务端命令客户端退出,则不更新,reason见官网
    if (reason && !reason.includes('disconnect')) {
      userOuting();
    }
    wsEmitFetch();
  });

  // 是否第一个用户来连,是的话更新首次连时间
  if (!wsNspModel().user.connect.firsttimer) {
    wsNspModel().user.connect.firsttimer = Date.now();
  }
  // 增加用户连接基数
  wsNspModel().user.connect.count++;
  // 拼凑从连接参数中传来的用户信息
  const { id, label } = socketQuery();
  const myUser = { id, label };

  // 对连接进入用户进行登记
  userComing();
  wsEmitFetch();

  // 用户交互信息处理
  wsOn('client-submit-msg', (res: any) => {
    wsBroadcast(
      'broadcast-msg',
      `${myUser.label}${res.type} 说:“${res.msg}`
    );
    wsEmit('to-msg-report', '消息发送成功', (res: any) => {
      console.log(666.2005, res);
    });
  });

  // 同步用户连接统计情况
  function wsEmitFetch() {
    wsBroadcast('broadcast-user-fetch', wsNspModel().user.connect);
  }
  // 用户连接上来后同步消息
  function wsEmitComing(data: any) {
    wsEmit('to-user-coming-data', data.item);
    wsBroadcast('broadcast-user-coming', data.msg);
  }
  // 用户离开后同步消息
  function wsEmitOuting(data: any) {
    wsBroadcast('broadcast-user-outing', data.msg);
  }

  // 连接用户初次处理
  function userComing() {
    const onIndex = wsNspModel().user.connect.online.findIndex(
      (el: any) => el.data.id === myUser.id
    );
    // 若在线
    if (onIndex > -1) {
      const onTmp = wsNspModel().user.connect.online[onIndex];
      wsCmdClose(onTmp);
      itemOuting(onTmp);
      itemComing(onTmp);
      wsEmitComing({
        msg: `${onTmp.count}次来,${myUser.label} 换了地方又来了!`,
        item: onTmp,
      });
    } else {
      userLive();
    }
  }

  // 用户强制下线命令
  function wsCmdClose(item: any) {
    item.countout++;
    const scid = item.data.id;
    // wsEmit(
    wsEmitTo(
      scid,
      'to-cmd-disconnect',
      scid + ',有用户在其他地方登录',
      (res: any) => {
        console.log(666.2009, res);
      }
    );
    wsClose(scid);
  }

  // 用户复活成在线状态
  function userLive() {
    const offIndex = wsNspModel().user.connect.offline.findIndex(
      (el: any) => el.data.id === myUser.id
    );
    if (offIndex > -1) {
      userLiveOffIndex(offIndex); // 如离线
    } else {
      userLiveNew(); // 如果新用户
    }
  }

  // 离线用户复活
  function userLiveOffIndex(offIndex: number) {
    if (offIndex > -1) {
      const offTmp = wsNspModel().user.connect.offline[offIndex];
      itemComing(offTmp);

      wsNspModel().user.connect.online.push(offTmp);
      wsNspModel().user.connect.offline.splice(offIndex, 1);

      wsEmitComing({
        msg: `${offTmp.count}次来,${myUser.label} 又来了!`,
        item: offTmp,
      });
    }
  }

  // 新用户入库
  function userLiveNew() {
    // 新用户,创建用户基本信息
    const onTmp = {
      id: socketId(),
      firsttimer: Date.now(),
      countout: 0,
      count: 1,
      counttimer: 0,
      ontimer: Date.now(),
      data: myUser,
    };

    wsNspModel().user.connect.online.push(onTmp);

    wsEmitComing({
      msg: `欢迎第1次访问,${myUser.label} 来了~`,
      item: onTmp,
    });
  }

  // 用户离开处理
  function userOuting() {
    const onIndex = wsNspModel().user.connect.online.findIndex(
      (el: any) => el.data.id === myUser.id
    );
    userOutingIndex(onIndex);
  }
  function userOutingIndex(onIndex: number) {
    // 处理在线时长
    if (onIndex > -1) {
      const offTmp = wsNspModel().user.connect.online[onIndex];
      itemOuting(offTmp);
      wsNspModel().user.connect.offline.push(offTmp);
      wsNspModel().user.connect.online.splice(onIndex, 1);

      wsEmitOuting({
        msg: `${wsNspModel().user.connect.count}${myUser.label} 走了~`,
        item: offTmp,
      });
    }
  }
  // 用户离开前数据更新
  function itemOuting(item: any) {
    item.counttimer += Date.now() - item.ontimer;
  }
  // 用户进入前数据更新
  function itemComing(item: any) {
    if (!item.firsttimer) {
      item.firsttimer = Date.now();
    }
    item.ontimer = Date.now();
    item.count++;
    item.id = socketId();
  }
};

web-dev\web-server\src\server\ws\online\user\connect\Model.ts

module.exports = () => {
  type IUserClient = { id: string; label: string };

  type IUser = {
    id: string;
    firsttimer: number;
    countout: number;
    count: number;
    counttimer: number;
    ontimer: number;
    data: IUserClient;
  };
  type IUsersList = IUser[] | any[];
  type IModel = {
    firsttimer: number;
    count: number;
    online: IUsersList;
    offline: IUsersList;
  };

  const Model: IModel = {
    firsttimer: 0, // 服务零点时间=第一个用户连接上来的时间
    count: 0, // 链接人次
    online: [], // 当前连接用户信息
    offline: [], // 离线用户信息
  };

  return Model;
};

web-dev\web-server\src\server\ws\online\broadcast\count\Index.ts

module.exports = (wsModel: any, nsp: string = '') => {
  const { wsNspModel, wsBroadcast } = require('../../../../../utils/Ws/Ws')(
    wsModel,
    nsp
  );

  // 这里演示一个服务器心跳广播的功能
  setInterval(() => {
    wsNspModel().broadcast.count++;
    // 所有在线的用户均可收到该广播
    wsBroadcast('broadcast-index', wsNspModel().broadcast.count);
  }, 1000);
};

web-dev\web-server\src\server\ws\online\broadcast\count\Model.ts

module.exports = () => {
  const Model: number = 0;

  return Model;
};

web-dev\web-client\src\utils\Ws.ts

import { io } from 'socket.io-client'; // 引入ws客户端插件

function Ws(url: any = '', opt: any = {}, nsp: string = '') {
  // 建立与服务器端的ws服务
  let ws: any;
  ws = io(url + '/' + nsp, opt);

  console.log(666.3002, url + '/' + nsp);

  // 监听到我连接到了ws服务
  function wsConnect(fn: any) {
    ws.on('connect', fn);
  }

  // 接收连接发来的消息
  function wsOn(id: string, fn: any) {
    ws.on(id, fn);
  }
  // 接收来指定发送的消息
  function wsOnTo(id: string, fn: any) {
    ws.on(id, fn);
  }
  // 接收来自广播的消息
  function wsOnBroadcast(id: string, fn: any) {
    ws.on(id, fn);
  }
  // 对当前连接发送消息
  function wsEmit(id: string, data: any, callback: any = null) {
    if (callback) {
      ws.emit(id, data, callback);
    } else {
      ws.emit(id, data);
    }
  }

  // 关闭连接
  function wsClose() {
    ws.disconnect();
  }
  // 当连接用户离开(断开连接)的时候
  function wsDisconnect(fn: any) {
    wsOn('disconnect', fn);
  }

  return {
    ws,
    wsConnect,
    wsOn,
    wsOnBroadcast,
    wsOnTo,
    wsEmit,
    wsClose,
    wsDisconnect,
  };
}
export default Ws;

web-dev\web-client\src\views\test\ws\User.vue(使用示例)

<script setup lang="ts">
import { onMounted, reactive, ref, toRaw } from 'vue';
import { ElMessage } from 'element-plus';
import Ws from '@/utils/Ws';
const props = defineProps({
  user: Object,
  nsp: String,
});

const { wsConnect, wsOn, wsOnBroadcast, wsOnTo, wsEmit, wsDisconnect } = Ws(
  'http://127.0.0.1:9098',
  {
    // 与服务器后端保持一致
    path: '/wsiot',
    // 传递用户信息
    query: props.user,
    //设置最大重试次数
    reconnectionAttempts: 5,
  },
  props.nsp || ''
);

const usersFetch: any = reactive({
  data: {},
});
const wsUser: any = reactive({
  data: {},
});
const msgData: any = ref([]);

// 初始化ws服务
function wsInit() {
  // 监听到我连接到了ws服务
  wsConnect(() => {
    console.log(666.601, 'connect');
  });

  //监听从服务器端回传的注销消息
  wsOnTo('to-cmd-disconnect', (res: any, callback: any) => {
    // 只有到服务器端有第三个回调函数时,才能回应这个callback消息
    callback(new Date() + ' 客户端获取了该消息');
    ElMessage(res);
  });

  wsOnBroadcast('broadcast-user-coming', (res: any) => {
    msgData.value.push(res);
  });

  wsOnTo('to-user-coming-data', (res: any) => {
    wsUser.data = res;
  });

  wsOnBroadcast('broadcast-user-outing', (res: any) => {
    msgData.value.push(res);
  });

  wsOnBroadcast('broadcast-user-fetch', (res: any) => {
    usersFetch.data = res;
  });

  wsOnBroadcast('broadcast-msg', (msg: string) => {
    console.log(666.3009, msg);
    msgData.value.push(msg);
  });

  //重试失败后会调用reconnect_failed事件
  wsOn('reconnect_failed', () => {
    ElMessage('reconnect_failed');
  });

  //重试失败后会调用reconnect_failed事件
  wsDisconnect((reason: any) => {
    ElMessage('disconnect:' + reason);
  });
}

const sliderValue = ref(0);

function onMsgIndex() {
  // 监听服务端实时心跳来的消息
  wsOnBroadcast('broadcast-index', (res) => {
    sliderValue.value = res % 100;
  });
}

const msgForm = reactive({
  msg: '',
  type: 0,
});

function onSubmit() {
  console.log(666.222, msgForm);
  wsEmit('client-submit-msg', toRaw(msgForm));
}

// 获取发送消息已传回
wsOnTo('to-msg-report', (res: any, callback: any) => {
  ElMessage(res);
  callback(new Date() + ' 客户端获取了该消息');
});

onMounted(() => {
  wsInit();
  onMsgIndex();
});
</script>

<template>
  <el-container class="as-area">
    <el-header height="60px">
      <el-progress
        :text-inside="true"
        :stroke-width="22"
        :percentage="sliderValue"
        status="warning"
      />
    </el-header>
    <el-main>
      <el-container class="as-area">
        <el-aside width="128px">
          <h1>离线</h1>
          <div v-for="item in usersFetch.data.offline">
            {{ item.data.label }}
          </div>
        </el-aside>
        <el-aside width="228px">
          <h1>在线</h1>
          <div v-for="item in usersFetch.data.online">
            {{ item.data.label }} - 【{{ item.id }}】
          </div>
        </el-aside>
        <el-main>
          <h1>公共信息</h1>
          <div v-for="item in msgData">{{ item }}</div>
        </el-main>
        <el-aside width="228px">
          <h1>个人信息</h1>
        </el-aside>
      </el-container>
    </el-main>
    <el-footer height="88px">
      <el-form :inline="true" :model="msgForm">
        <el-form-item label="消息">
          <el-input v-model="msgForm.msg" placeholder="消息" />
        </el-form-item>
        <el-form-item label="地址">
          <el-select v-model="msgForm.type" placeholder="地址">
            <el-option label="南京" :value="1" />
            <el-option label="纽约" :value="2" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="onSubmit">提交</el-button>
          {{ wsUser.data }}
        </el-form-item>
      </el-form>
    </el-footer>
  </el-container>
</template>

<style scoped lang="scss">
.el-container {
  height: 100%;
  max-height: 100%;
  overflow: auto;
}
</style>

常用数据流设计

A用户在S1空间发消息
	发往S1空间的B用户socket[B].emit
		接收socket[B].on
	发往S1空间所有用户socket.broadcast.emit
		接收socket.on
	发往S2空间所有用户socket[S2].broadcast.emit
		接收socket[S2].on
服务器从S1空间发消息
	发往S1空间的A用户socket[A].emit
		接收socket.on
	发往S1空间的B用户socket[B].emit
		接收socket[B].on
	发往S1空间所有用户socket.broadcast.emit
		接收socket.on
	发往S2空间所有用户socket[S2].broadcast.emit
		接收socket[S2].on
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿赛工作室

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值