socket.io + redis + expressjs cluster - 在expressjs请求中获取套接字对象

nad*_*ada 5 cluster-computing redis node.js express socket.io

基于这个答案的问题:https://stackoverflow.com/a/18650183/4478897

我试图找到这个解决方案,但似乎没有任何东西可以按照我需要的方式工作.

集群expressjs,socket.io我们可以使用redis共享会话并ioioworld(io.sockets.on('connection',...)内发送消息.问题是我们是想socket.join/leaveexpressjs世界里发送消息(或使用简单的)(route.get/post).

如果我们不使用集群,我们可以atach客户socket对象明确request对象(或简单地exportio对象),然后在任何GET/POST路线随时使用它.

在另一方面,如果我们的集群和使用所提到的方法来获取socket里面的对象expressjs世界,有时socket对象,因为未定义socket此客户端对象在其他初始化worker.

一些示例流程:

  • 客户端连接到http:// localhostworker 1处理此请求.
  • 加载页面后,客户端连接到socket.io.Worker 2处理此连接.
  • 客户端再次执行POST worker 1worker X处理此请求.

在这种情况下,当客户端执行POST时,只worker 2知道socket该客户端的对象.所以这将得到一个未定义的socket对象.

那么,问题是:

我们如何socket从任何客户端对象中获取worker它以在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

nad*_*ada -1

好吧,终于尝试了代码,它可以工作(有一些拼写错误的修改和其他事情),但我确信这需要在某个地方有更好的代码。所以我愿意接受更多答案!

当授权客户端套接字和其他一些东西时,此代码是我的 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);
        }
      }
    }
  });
Run Code Online (Sandbox Code Playgroud)

然后只需导出模块并将其附加到您的expressjsrequest => 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!');
});
Run Code Online (Sandbox Code Playgroud)