概述
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-devweb-serversrcutilsWsIndex.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-devweb-serversrcutilsWsWs.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-devweb-serversrcserverwsindex.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-devweb-serversrcserverwsconfig.json
{
"nsp": {
"index": {
"user": ["connect"],
"broadcast": ["count"]
},
"online": {
"user": ["connect"],
"broadcast": ["count"]
}
}
}
web-devweb-serversrcserverwsonlineuserconnectIndex.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-devweb-serversrcserverwsonlineuserconnectModel.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-devweb-serversrcserverwsonlinebroadcastcountIndex.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-devweb-serversrcserverwsonlinebroadcastcountModel.ts
module.exports = () => {
const Model: number = 0;
return Model;
};
web-devweb-clientsrcutilsWs.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-devweb-clientsrcviewstestwsUser.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
最后
以上就是苗条白云为你收集整理的049关于Socket.IO的功能预研与示例解析049关于Socket.IO的功能预研与示例解析的全部内容,希望文章能够帮你解决049关于Socket.IO的功能预研与示例解析049关于Socket.IO的功能预研与示例解析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复