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

Jon*_*mpf 6 javascript amazon-s3 node.js socket.io

我正在使用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);
Run Code Online (Sandbox Code Playgroud)

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;   
};
Run Code Online (Sandbox Code Playgroud)

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);
});
};
Run Code Online (Sandbox Code Playgroud)

当使用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
Run Code Online (Sandbox Code Playgroud)

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

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

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
Run Code Online (Sandbox Code Playgroud)

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

Jav*_*nde 4

您发布的第二个代码示例应该可以工作,如果没有,您应该发布更多代码。

据我了解,套接字连接到“连接”上的默认房间,该房间由客户端的“id”镜像。根据官方文档,使用 socket.to(id).emit() 应该仅将数据发送到该客户端,但这对我不起作用。

Socket.io 比这容易得多。下面的代码将在每个客户端连接时向它们发送“hello”消息:

io.sockets.on('connection', function (socket) {
  socket.emit('hello');
});
Run Code Online (Sandbox Code Playgroud)

每次新客户端连接到 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'
    });
...
Run Code Online (Sandbox Code Playgroud)

现在您应该明白socket.join(socket.id)这没有意义,因为没有套接字会共享套接字 ID。

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

你这里有两个问题,首先:

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

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

另一个问题是您没有链接套接字和 s3 操作。socket.js这是合并s3upload.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);
    });
};
Run Code Online (Sandbox Code Playgroud)