[英]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.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);
});
};
根據文檔,所有用戶都加入了套接字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.