簡體   English   中英

Socket.io無法將數據發送到客戶端的獨特房間

[英]Socket.io unable to emit data to client's unique room

我正在使用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

我在這做錯了什么? 是否有不同的方法將事件從服務器發送到我缺少的特定客戶端?

您發布的第二個代碼示例應該可以使用,如果沒有,您應該發布更多代碼。

據我所知,套接字連接到'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);
    });
};

根據文檔,所有用戶都加入了套接字ID標識的默認空間 ,因此您無需加入連接。 仍然根據這一點,如果你想從特定套接字發送到命名空間中的房間你應該使用socket.broadcast.to(room).emit('my message', msg) ,因為你想要廣播消息連接到該特定房間的所有客戶。

所有新連接都自動連接到名稱與其socket.id相同的房間。 您可以使用它向特定用戶發送消息,但您必須知道與此用戶初始化的連接關聯的socket.id 您必須決定如何管理這種關聯(通過數據庫,或通過為其創建數組在內存中),但是一旦擁有它,只需通過以下方式發送進度百分比:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM