代码之家  ›  专栏  ›  技术社区  ›  nada

插座io+redis+expressjs集群-在expressjss请求中获取套接字对象

  •  6
  • nada  · 技术社区  · 10 年前

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

    我试图找到这个解决方案,但似乎没有什么能满足我的需要。

    群集 expressjs 和 socket.io 我们可以使用redis共享会话并发送 io 内部消息 国际奥委会 世界( io.sockets.on('connection', ...). 问题是,如果我们想发送消息(或使用简单的 socket.join/leave )在 表达式js 世界( route.get/post ).

    如果我们不使用集群,我们可以访问客户端 socket 反对快车 request 对象(或简单地 export 这个 国际奥委会 对象),然后在任何GET/POST路由上随时使用它。

    另一方面,如果我们进行聚类并使用上述方法获得 插座 对象内部 表达式js 世界,有时 插座 对象未定义,因为 插座 此客户端的对象在其他 worker .

    流程示例:

    • 客户端连接到 http://localhost 和 worker 1 处理此请求。
    • 页面加载后,客户端连接到 插座.io . Worker 2 处理此连接。
    • 客户端执行POST并再次 工人1 或 worker X 处理此请求。

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

    因此,问题是:

    我们怎样才能找到客户 插座 任何对象 工人 重复使用 expressjs request 对象

    也许我的代码是错误的,但几乎就像上面提到的答案的链接。


    笔记

    • 不想使用某种代理。
    • 不想迁移到其他库(expressio、sockjs…)
    • 对不起我的英语:)

    使用最后一个节点,套接字。io、expressjs、套接字。io redis,redis…版本

    不要犹豫,要问点什么!


    更新1

    可能的解决方案,但仍需测试。不知道这是不是一个真正好的解决方案。

    • 更新3 :根据我自己的答案编写代码

    更新2

    类似更新1,但使用 https://nodejs.org/dist/latest-v5.x/docs/api/cluster.html#cluster_event_message

    2 回复  |  直到 9 年前
        1
  •  1
  •   Community Mohan Dere    9 年前

    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 .

        2
  •  -1
  •   nada    10 年前

    我们终于尝试了这段代码,它很管用(有一些拼写错误的修改和其他事情),但我确信这需要一个更好的代码。所以我愿意接受更多的答案!

    这个代码是我套接字的一部分。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!');
    });