socket.io+redis+expressjs 集群 - 在 expressjs 请求中获取套接字对象
Posted
技术标签:
【中文标题】socket.io+redis+expressjs 集群 - 在 expressjs 请求中获取套接字对象【英文标题】:socket.io+redis+expressjs cluster - get socket object in expressjs request 【发布时间】:2016-05-20 16:43:51 【问题描述】:基于此答案的问题:https://***.com/a/18650183/4478897
我试图找到这个解决方案,但似乎没有什么能按我需要的方式工作。
集群expressjs
和socket.io
我们可以使用redis共享会话并在io
世界(io.sockets.on('connection',
...)中发送io
消息。问题是我们是否想在expressjs
世界(route.get/post
)中发送消息(或使用简单的socket.join/leave
)。
如果我们不使用集群,我们可以将客户端 socket
对象附加到 express request
对象(或简单地将 export
io
对象),然后在任何 GET/POST 路由上随时使用它.
另一方面,如果我们进行聚类并使用上述方法获取expressjs
世界中的socket
对象,则有时socket
对象未定义,因为此客户端的socket
对象已初始化在其他worker
。
一些示例流程:
客户端连接到http://localhost,worker 1
处理此请求。
页面加载后,客户端连接到socket.io
。 Worker 2
处理此连接。
客户端执行 POST 并再次 worker 1
或 worker X
处理此请求。
在这种情况下,当客户端执行 POST 时,只有 worker 2
知道此客户端的 socket
对象。所以这将得到一个未定义的socket
对象。
那么问题来了:
我们如何从任何worker
获取客户端socket
对象以在expressjs request
对象上重用它。
也许我的代码是错误的,但几乎就像上面提到的答案的链接。
注意事项
不想使用某种代理。 不想迁移到其他库(expressio、sockjs...) 对不起我的英语:)使用最后的nodejs、socket.io、expressjs、socket.io-redis、redis...版本
请不要犹豫!
更新 1
可能的解决方案,但仍需要测试。不知道这是否真的很好:解决方案。
更新 3:我自己回答的工作代码更新 2
与更新 1 类似,但使用 https://nodejs.org/dist/latest-v5.x/docs/api/cluster.html#cluster_event_message
【问题讨论】:
【参考方案1】:remoteJoin
和 remoteLeave
方法被添加到 socket.io-redis 3.0.0
:
io.adapter.remoteJoin('<my-id>', 'room1', function (err)
if (err) /* unknown id */
// success
);
io.adapter.remoteLeave('<my-id>', 'room1', function (err)
if (err) /* unknown id */
// success
);
注意:实现看起来很像答案above。
【讨论】:
我看到了合并。还是谢谢你:D【参考方案2】:好吧,终于尝试了代码并且它可以工作(有一些拼写错误的修改和其他东西),但我确信在某个地方需要一个更好的代码。所以我愿意接受更多答案!
当授权客户端套接字和其他一些东西时,此代码是我的 socket.io 模块的一部分......
var redis = require("redis");
var redisPub = redis.createClient();
var redisSub = redis.createClient();
var PubSubChannel = "clusterChannel";
// Function that checks if this worker knows the socket object of this socketId.
// If not, publish the message to all the other sockets (workers)
io.socketDo = function (type, socketId, roomName)
if (typeof io.sockets.connected[socketId] != "undefined")
if (type === "join")
return io.sockets.connected[socketId].join(roomName);
if (type === "leave")
return io.sockets.connected[socketId].leave(roomName);
else
redisPub.publish(
PubSubChannel,
JSON.stringify(
type: type,
socketId: '' + socketId,
roomName: roomName
)
);
;
// Subscribe to some channel
redisSub.subscribe(PubSubChannel);
// When this worker receive a message from channel "PubSubChannel" checks
// if it have the socket object for this socketId and do the operation
redisSub.on("message", function (channel, data)
data = JSON.parse(data);
var type = data.type;
var socketId = data.socketId;
var roomName = data.roomName;
if ((type === "join" || type === "leave") && channel == PubSubChannel)
if (typeof io.sockets.connected[socketId] != "undefined")
if (type === "join")
return io.sockets.connected[socketId].join(roomName);
if (type === "leave")
return io.sockets.connected[socketId].leave(roomName);
);
然后只需简单地导出模块并将其附加到您的 expressjs request => req.io = io
// req.session.socketId value is fetched on "io.sockets.on('connection', function(socket) "
// by express to socket.io using redis shared sessions
app.get('/', function (req, res)
req.io.socketDo('join', req.session.socketId, 'someRoomToJoin');
// IT WORKS!
req.io.sockets.in('someRoomToJoin').emit('text');
req.io.socketDo('leave', req.session.socketId, 'someRoomToLeave');
res.send('Hello World!');
);
【讨论】:
以上是关于socket.io+redis+expressjs 集群 - 在 expressjs 请求中获取套接字对象的主要内容,如果未能解决你的问题,请参考以下文章
expressJS 和 socket.io 监听不同的端口和 socket.io 客户端连接
带有 socket.io 和 expressjs 的节点集群
如何在同一个端口上使用 ExpressJS 和 Socket.io?