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

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

我遇到的问题是socket.io中的.emit事件将上传进度数据发送给所有连接的客户端,而不仅仅是发起上传的客户端。 据我了解,一个套接字连接到'连接',这是由客户端'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 = *节点myapp.js时,我看到了socket.io-parsing器在这个信息中,但是没有发送给客户端:

 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部分,它会将数据发送到客户端(尽pipe对于所有客户端来说,根本没有任何帮助):

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

DEBUG = *节点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 

我在这里做错了什么? 有没有不同的方式发送事件从服务器到只有特定的客户端,我失踪?

你发布的代码的第二个例子应该工作,如果没有,你应该发布更多的代码。

据我了解,一个套接字连接到'连接',这是由客户端'ID'镜像的默认房间。 根据官方文档,使用socket.to(id).emit()应该将数据范围只发送到客户端,但这不适合我。

Socket.io比这更简单。 下面的代码会在连接时向每个客户端发送一个“hello”消息:

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

每当一个新的客户端连接到socket.io服务器,它将使用该特定的套接字作为参数运行指定的callback。 socket.id只是一个唯一的代码来标识这个套接字,但是你并不需要这个variables,上面的代码展示了如何通过一个特定的socket发送消息。

Socket.io还为您提供了一些function来创build名称空间/房间,以便您可以将某些标识符(房间名称)下的连接组合起来,并能够将消息广播到所有人:

 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操作。 这里是一个解决scheme,合并在同一个文件中的socket.jss3upload.js 。 如果你真的需要保持它们分开,你将需要find一个不同的方式来连接套接字连接到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); }); }; 

根据文档,所有的用户join由套接字标识标识的默认空间 ,所以不需要你join连接。 依然如此,如果你想从一个特定的套接字发送到名字空间的一个房间,你应该使用socket.broadcast.to(room).emit('my message', msg) ,假设你想广播消息给连接到特定房间的所有客户。

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

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