集群节点应用程序时 Socket.io websocket 授权失败

发布于 2025-01-05 01:35:56 字数 2251 浏览 1 评论 0原文

问题:是否可以对使用 Socket.io 提供 WebSocket 支持的应用程序进行集群?如果是这样,最好的实施方法是什么?

我构建了一个基于 Node.js 的使用 Express 和 Socket.io 的应用程序。我想合并集群以增加我的应用程序可以处理的请求量。

以下导致我的应用程序产生套接字握手错误...

var cluster = require('cluster');
var numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  // Fork workers.
  for (var i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('death', function(worker) {
    console.log('worker ' + worker.pid + ' died');
  });
} else {
  app.listen(3000);  
}

控制台日志显示 socket.io 正在启动多次。

jack@jack:~$ node nimble/app.js
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started

Socket.io 是目前正在我的服务器代码顶部使用:

var io = require('socket.io').listen(app);

Websocket 授权代码:

//Auth the user
io.set('authorization', function (data, accept) {
  // check if there's a cookie header
  if (data.headers.cookie) {
    data.cookie = parseCookie(data.headers.cookie);
    data.sessionID = data.cookie['express.sid'];

    //Save the session store to the data object
    data.sessionStore = sessionStore;

    sessionStore.get(data.sessionID, function(err, session){
      if(err) throw err;

      if(!session)
      {
        console.error("Error whilst authorizing websocket handshake");
        accept('Error', false);
      }
      else
      {
        console.log("AUTH USERNAME: " + session.username);
        if(session.username){
          data.session = new Session(data, session);
          accept(null, true);
        }else {
          accept('Invalid User', false);
        }       

      }
    })
  } else {
    console.error("No cookie was found whilst authorizing websocket handshake");
    return accept('No cookie transmitted.', false);
  }
});

错误消息的控制台日志:

Error whilst authorizing websocket handshake
   debug - authorized
   warn  - handshake error Error

Question: Is it possible to cluster an application which is using Socket.io for WebSocket support? If so what would be the best method of implementation?

I've built an application which uses Express and Socket.io, built on Node.js. I'd like to incorporate clustering to increase the amount of requests that my application can process.

The following causes my application to produce a socket handshake error...

var cluster = require('cluster');
var numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  // Fork workers.
  for (var i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('death', function(worker) {
    console.log('worker ' + worker.pid + ' died');
  });
} else {
  app.listen(3000);  
}

A console log shows that socket.io is being started up multiple times.

jack@jack:~$ node nimble/app.js
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started
   info  - socket.io started

Socket.io is currently being set up in the top of my server code using:

var io = require('socket.io').listen(app);

The websocket authorization code:

//Auth the user
io.set('authorization', function (data, accept) {
  // check if there's a cookie header
  if (data.headers.cookie) {
    data.cookie = parseCookie(data.headers.cookie);
    data.sessionID = data.cookie['express.sid'];

    //Save the session store to the data object
    data.sessionStore = sessionStore;

    sessionStore.get(data.sessionID, function(err, session){
      if(err) throw err;

      if(!session)
      {
        console.error("Error whilst authorizing websocket handshake");
        accept('Error', false);
      }
      else
      {
        console.log("AUTH USERNAME: " + session.username);
        if(session.username){
          data.session = new Session(data, session);
          accept(null, true);
        }else {
          accept('Invalid User', false);
        }       

      }
    })
  } else {
    console.error("No cookie was found whilst authorizing websocket handshake");
    return accept('No cookie transmitted.', false);
  }
});

Console log of the error message:

Error whilst authorizing websocket handshake
   debug - authorized
   warn  - handshake error Error

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

荆棘i 2025-01-12 01:35:56

您的 sessionStore 是什么?如果它是 connect 附带的 MemoryStore,则会话不会在您的工作人员之间共享。每个工作人员都有自己的一组会话,如果客户端连接到另一个工作人员,您将找不到他们的会话。我建议您查看 connect-redis 在进程之间共享会话。基本用法:

var connect = require('connect')
  , RedisStore = require('connect-redis')(connect);

var app = connect.createServer();
app.use(connect.session({store: new RedisStore, secret: 'top secret'});

当然,这需要你也设置好redis。在 Connect wiki 上有 CouchDB、memcached、postgres 等模块。

不过,这只能解决您的部分问题,因为现在您已经在工作人员之间共享了会话,但是 socket.io 无法向连接到其他工作人员的客户端发送消息。基本上,如果您在一个工作线程中发出 socket.emit ,该消息只会发送到连接到同一工作线程的客户端。解决此问题的一种方法是使用 RedisStore for socket.io,它利用 Redis 在工作线程之间路由消息。基本用法:

var sio = require('socket.io')
  , RedisStore = sio.RedisStore
  , io = sio.listen(app);

io.set('store', new RedisStore);

现在,所有消息都应该路由到客户端,无论它们连接到哪个工作线程。

另请参阅:Node.js、多线程和 Socket.io

What is your sessionStore? If it's the MemoryStore shipped with connect, then sessions won't be shared between your workers. Each worker will have it's own set of sessions, and if a client connects to another worker, you wont find their session. I suggest you take a look at e.g. connect-redis for sharing sessions between processes. Basic usage:

var connect = require('connect')
  , RedisStore = require('connect-redis')(connect);

var app = connect.createServer();
app.use(connect.session({store: new RedisStore, secret: 'top secret'});

Of course, this requires that you also set up redis. Over at the Connect wiki there are modules for CouchDB, memcached, postgres and others.

This only solves part of your problem, though, because now you have sessions shared between workers, but socket.io has no way of sending messages to clients which are connected to other workers. Basically, if you issue a socket.emit in one worker, that message will only be sent to clients connected to that same worker. One solution to this is to use RedisStore for socket.io, which leverages redis to route messages between workers. Basic usage:

var sio = require('socket.io')
  , RedisStore = sio.RedisStore
  , io = sio.listen(app);

io.set('store', new RedisStore);

Now, all messages should be routed to clients no matter what worker they are connected to.

See also: Node.js, multi-threading and Socket.io

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文