首页 文章

Socket.io无法向客户端的独特房间发送数据

提问于
浏览 1200
6

我正在使用Node.js来创建媒体上传微服务 . 此服务的工作原理是将上传的二进制数据输入缓冲区,然后使用S3 npm包上传到S3存储桶 . 我正在尝试使用该包中的eventEmitter,它显示上传到S3的数据量,并将其发送回正在进行上载的客户端(以便他们可以看到上传进度) . 我正在使用socket.io将进度数据发送回客户端 .

我遇到的问题是socket.io中的.emit事件会将上传进度数据发送到所有连接的客户端,而不仅仅是发起上传的客户端 . 据我所知,套接字连接到'connection'上的默认房间,该房间由客户端的'id'镜像 . 根据官方文档,使用socket.to(id).emit()应该只将范围内的数据发送到该客户端,但这对我不起作用 .

更新示例代码:

server.js:

var http = require('http'),
users = require('./data'),
app = require('./app')(users);

var server = http.createServer(app);

server.listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

var io = require('./socket.js').listen(server);

socket.js:

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

var socketConnection = exports = module.exports = {};

socketConnection.listen = function listen(app) {
    io = socketio.listen(app);
    exports.sockets = io.sockets;

    io.sockets.on('connection', function (socket) {
        socket.join(socket.id);
        socket.on('disconnect', function(){
            console.log("device "+socket.id+" disconnected");
        });
        socketConnection.upload = function upload (data) {
        socket.to(socket.id).emit('progress', {progress:(data.progressAmount/data.progressTotal)*100});
    };
});
return io;   
};

s3upload.js:

var config = require('../config/aws.json');
var s3 = require('s3');
var path = require('path');
var fs = require('fs');
var Busboy = require('busboy');
var inspect = require('util').inspect;

var io = require('../socket.js');
...
var S3Upload = exports = module.exports = {};
....
S3Upload.upload = function upload(params) {
// start uploading to uploader
var uploader = client.uploadFile(params);

uploader.on('error', function(err) {
    console.error("There was a problem uploading the file to bucket, either the params are incorrect or there is an issue with the connection: ", err.stack);
    res.json({responseHTML: "<span>There was a problem uploading the file to bucket, either the params are incorrect or there is an issue with the connection. Please refresh and try again.</span>"});
    throw new Error(err);
}),

uploader.on('progress', function() {
    io.upload(uploader);
}),

uploader.on('end', function(){
    S3Upload.deleteFile(params.localFile);
});
};

当使用DEBUG = * node myapp.js时,我看到socket.io-parser接收了这些信息,但它没有将它发送到客户端:

socket.io-parser encoding packet {"type":2,"data":["progress",{"progress":95.79422221709825}],"nsp":"/"} +0ms


socket.io-parser encoded {"type":2,"data":["progress",{"progress":95.79422221709825}],"nsp":"/"} as 2["progress",{"progress":95.79422221709825}] +0ms

但是,如果我删除此代码的.to部分,它会将数据发送到客户端(尽管对所有客户端都没有帮助):

io.sockets.on('connection', function(socket) {
    socket.join(socket.id);
    socket.emit('progress', {progress: (data.progressAmount/data.progressTotal)*100});
});

DEBUG = * node myapp.js:

socket.io:client writing packet {"type":2,"data":["progress",{"progress":99.93823786632886}],"nsp":"/"} +1ms
  socket.io-parser encoding packet {"type":2,"data":["progress",{"progress":99.93823786632886}],"nsp":"/"} +1ms
  socket.io-parser encoded {"type":2,"data":["progress",{"progress":99.93823786632886}],"nsp":"/"} as 2["progress",{"progress":99.93823786632886}] +0ms
  engine:socket sending packet "message" (2["progress",{"progress":99.93823786632886}]) +0ms
  engine:socket flushing buffer to transport +0ms
  engine:ws writing "42["progress",{"progress":99.84186540937002}]" +0ms
  engine:ws writing "42["progress",{"progress":99.93823786632886}]" +0ms

我在这做错了什么?是否有不同的方法将事件从服务器发送到我缺少的特定客户端?

3 回答

  • 3

    根据文档,所有用户都加入了由套接字ID标识的default room,因此您无需加入连接 . 仍然根据这一点,如果你想从特定套接字发送到命名空间中的房间,你应该使用 socket.broadcast.to(room).emit('my message', msg) ,因为你想要将消息广播到连接到该特定房间的所有客户端 .

  • 1

    您发布的第二个代码示例应该可以使用,如果没有,您应该发布更多代码 .

    据我所知,套接字连接到'connection'上的默认房间,该房间由客户端的'id'镜像 . 根据官方文档,使用socket.to(id).emit()应该只将范围内的数据发送到该客户端,但这对我不起作用 .

    Socket.io比这简单得多 . 以下代码将在每个客户端连接时向其发送“hello”消息:

    io.sockets.on('connection', function (socket) {
      socket.emit('hello');
    });
    

    每当新客户端连接到socket.io服务器时,它将使用该特定套接字作为参数运行指定的回调 . socket.id 只是识别该套接字的唯一代码,但您并不真正需要该变量,上面的代码向您展示了如何通过特定的 socket 发送消息 .

    Socket.io还为您提供了一些创建命名空间/房间的功能,因此您可以在某个标识符(房间名称)下对连接进行分组,并能够向所有节点广播消息:

    io.sockets.on('connection', function (socket) {
        // This will be triggered after the client does socket.emit('join','myRoom')
        socket.on('join', function (room) {
            socket.join(room); // Now this socket will receive all the messages broadcast to 'myRoom'
        });
    ...
    

    现在您应该了解 socket.join(socket.id) 只是没有意义,因为没有套接字将共享套接字ID .

    编辑以使用新代码回答问题:

    你有两个问题,第一个:

    socketConnection.upload = function upload (data) {
            socket.to(socket.id).emit('progress', {progress:(data.progressAmount/data.progressTotal)*100});
        };
    

    请注意,在上面的代码中,每次客户端连接到服务器时,都会运行 io.sockets.on('connection',function (socket) { 内的所有内容 . 您正在覆盖该函数以将其指向最新用户的套接字 .

    另一个问题是您没有链接套接字和s3操作 . 这是在同一文件中合并 socket.jss3upload.js 的解决方案 . 如果你真的需要将它们分开,你需要找到一种不同的方法来将套接字连接链接到s3操作:

    var config = require('../config/aws.json');
    var s3 = require('s3');
    var path = require('path');
    var fs = require('fs');
    var Busboy = require('busboy');
    var inspect = require('util').inspect;
    var io = require('socket.io');
    
    var socketConnection = exports = module.exports = {};
    var S3Upload = exports = module.exports = {};
    
    io = socketio.listen(app);
    exports.sockets = io.sockets;
    
    io.sockets.on('connection', function (socket) {
    
        socket.on('disconnect', function(){
            console.log("device "+socket.id+" disconnected");
        });
    
        socket.on('upload', function (data) { //The client will trigger the upload sending the data
            /*
                some code creating the bucket params using data
            */
            S3Upload.upload(params,this);
        });
    });
    
    S3Upload.upload = function upload(params,socket) { // Here we pass the socket so we can answer him back
        // start uploading to uploader
        var uploader = client.uploadFile(params);
    
        uploader.on('error', function(err) {
            console.error("There was a problem uploading the file to bucket, either the params are incorrect or there is an issue with the connection: ", err.stack);
            res.json({responseHTML: "<span>There was a problem uploading the file to bucket, either the params are incorrect or there is an issue with the connection. Please refresh and try again.</span>"});
            throw new Error(err);
        }),
    
        uploader.on('progress', function() {
            socket.emit('progress', {progress:(uploader.progressAmount/uploader.progressTotal)*100});
        }),
    
        uploader.on('end', function(){
            S3Upload.deleteFile(params.localFile);
        });
    };
    
  • 1

    所有新连接都自动连接到名称与其socket.id相同的房间 . 您可以使用它向特定用户发送消息,但您必须知道与此用户初始化的连接关联的 socket.id . 您必须决定如何管理这种关联(通过数据库,或通过为其创建数组在内存中),但是一旦拥有它,只需通过以下方式发送进度百分比:

    socket.broadcast.to( user_socket_id ).emit( "progress", number_or_percent );
    

相关问题