Nodejs中socket.io的同步问题

Nodejs中socket.io的同步问题

function broadcastEvents(evt, args) { // convert args to array args = args ? Array.prototype.slice.call(args) : []; console.log(evt, args); args.unshift(evt); console.log(args); var audience = broadcast.audience; for (var audId in audience) audience[audId].emit.apply(audience[audId], args); } socket.onEvent = function (evt, func) { socket.on(evt, function () { // If func return true, broadcast it if (func.apply(this, arguments)) broadcastEvents(evt, arguments); }); }; socket.onEvent(‘draw circle’, function (x, y, color, width) { canvas.drawing = { type: ‘circle’, color: color, width: width, points: [{x: x, y: y}] }; return true; });


3 回复

在 Node.js 中使用 socket.io 进行实时通信时,经常会遇到同步问题。特别是在需要广播事件给多个客户端时,确保所有操作按预期顺序执行是非常重要的。

以下是一个示例代码,展示了如何处理 socket.io 的同步问题,并通过广播事件来更新所有客户端的状态。

示例代码

const io = require('socket.io')(server);

let broadcast = {
    audience: {}
};

function broadcastEvents(evt, args) {
    // 将 args 转换为数组
    args = args ? Array.prototype.slice.call(args) : [];
    console.log(evt, args);
    args.unshift(evt);  // 在参数列表前添加事件名
    console.log(args);

    let audience = broadcast.audience;
    for (let audId in audience) {
        if (audience.hasOwnProperty(audId)) {
            audience[audId].emit.apply(audience[audId], args);
        }
    }
}

io.on('connection', (socket) => {
    console.log('A user connected:', socket.id);

    socket.on('add-client', (clientId) => {
        broadcast.audience[clientId] = socket;
        console.log('Client added:', clientId);
    });

    socket.onEvent = function (evt, func) {
        socket.on(evt, function () {
            // 如果 func 返回 true,则广播该事件
            if (func.apply(this, arguments)) {
                broadcastEvents(evt, arguments);
            }
        });
    };

    socket.onEvent('draw-circle', function (x, y, color, width) {
        canvas.drawing = {
            type: 'circle',
            color: color,
            width: width,
            points: [{ x: x, y: y }]
        };
        return true;
    });

    socket.on('disconnect', () => {
        console.log('User disconnected:', socket.id);
        delete broadcast.audience[socket.id];
    });
});

const server = require('http').createServer();
server.listen(3000, () => {
    console.log('Server listening on port 3000');
});

解释

  1. 初始化:

    • 使用 socket.io 创建一个服务器实例。
    • 定义 broadcast 对象用于存储连接的客户端。
  2. 广播函数:

    • broadcastEvents 函数负责将事件和参数广播给所有客户端。它首先将参数转换为数组,并在参数列表前添加事件名,然后遍历 broadcast.audience 并发送事件。
  3. 事件监听器:

    • 当客户端连接时,将其添加到 broadcast.audience 中。
    • 定义 socket.onEvent 方法,用于监听特定事件并调用回调函数。如果回调函数返回 true,则触发广播事件。
  4. 事件处理:

    • draw-circle 事件处理函数更新画布状态,并返回 true 以触发广播。
  5. 断开连接:

    • 当客户端断开连接时,从 broadcast.audience 中删除对应的客户端。

通过这种方式,可以确保在客户端连接、事件触发和广播时,操作能够按预期顺序执行,从而避免同步问题。


不好意思,还没有问问题就不小心给发布了。 我想问的是,上面的代码并没有emit(event,data)的形式,怎么就能实现响应绘图事件,并把事件数据广播至别的客户端的。还有就是apply真不懂,能给详细解释下吗? 谢谢了。

在Node.js中使用socket.io进行事件广播时,经常会遇到异步问题。这是因为socket.io是基于事件驱动的异步框架,而你的代码需要确保广播事件在正确的时间点触发。

示例代码

假设我们有一个简单的场景,其中客户端发送一个draw circle事件,并且服务器需要广播这个事件给所有连接的客户端。我们可以通过以下方式实现:

const io = require('socket.io')(server);

let broadcast = {
    audience: {}
};

io.on('connection', socket => {
    console.log('a user connected');
    
    socket.on('disconnect', () => {
        console.log('user disconnected');
    });

    // Function to broadcast events to all clients
    function broadcastEvents(evt, args) {
        args = args ? Array.prototype.slice.call(args) : [];
        args.unshift(evt);
        for (let clientSocket of Object.values(broadcast.audience)) {
            clientSocket.emit.apply(clientSocket, args);
        }
    }

    // Function to handle and broadcast custom events
    socket.onEvent = function (evt, func) {
        socket.on(evt, function (...args) {
            if (func.apply(this, args)) {
                broadcastEvents(evt, args);
            }
        });
    };

    // Register a custom event
    socket.onEvent('draw circle', function (x, y, color, width) {
        canvas.drawing = {
            type: 'circle',
            color: color,
            width: width,
            points: [{x: x, y: y}]
        };
        return true; // Return true to trigger the broadcast
    });

    // Add the socket to the audience list
    broadcast.audience[socket.id] = socket;
});

解释

  1. 广播函数 (broadcastEvents):

    • 这个函数接收事件名和参数,然后将这些信息广播给所有连接的客户端。
    • args.unshift(evt) 将事件名添加到参数列表的最前面,以便在广播时传递完整的信息。
  2. 事件处理器 (onEvent):

    • 这个函数用于注册自定义事件处理器。当接收到指定事件时,它会调用传入的回调函数。
    • 如果回调函数返回true,则调用广播函数来广播事件。
  3. 连接处理 (io.on('connection')):

    • 每当一个新的客户端连接时,将该客户端添加到broadcast.audience对象中。
    • 当客户端断开连接时,从broadcast.audience中移除该客户端。

通过这种方式,你可以确保在适当的时间点广播事件,并避免同步问题。

回到顶部