【问题标题】:Node.js .. Socket.io connection increase on every page refreshNode.js .. Socket.io 连接在每次页面刷新时增加
【发布时间】:2018-01-10 11:35:29
【问题描述】:

希望你能解决我的问题。


我在“app.js”文件中有这段代码

var express = require('express');
var app = express();
const stores = require('./routes/r_stores');
var server = require('http').createServer(app);
var io = require('socket.io')(server);
app.io=io;

app.use('/stores',stores);
// update question
io.on('connection',function(socket){
  console.log("IO APP CONNECTED  ");
  socket.on('disconnect',function(){
    console.log("IO APP DISCONNECT  ");
  }) 
})
server.listen(3080, function () {
    console.log('listening on port 3080');
});

在“r_stores.js”文件中

var express = require('express');
var router = express.Router();
var app = express();
router.get('/', function (req, res, next) {
   req.app.io.on('connection', function(socket){
          console.log("IO STORES CONNECTED");
          socket.on('disconnect',function(){
            console.log("IO STORES DISCONNECTED");
          })
   })
})
module.exports = router;

客户端刷新页面时的问题,Socket IO增加了一个用户的连接,当我发出一条消息时,它会按连接数发送给客户端。

刷新时,控制台显示这个

第一次刷新时

IO 应用已连接

已连接 IO 商店

在第二次刷新时

IO 应用已连接

已连接 IO 商店

已连接 IO 商店

第三次刷新

IO 应用已连接

已连接 IO 商店

已连接 IO 商店

已连接 IO 商店

【问题讨论】:

  • 我认为客户端代码在启动/初始化时连接到 io 服务器,这会导致它在每次刷新时连接到 websocket
  • 我在“app.js”中使用了socket io,即使多次刷新也能正常工作。 router.get ('/') 和导出的问题.. 我的意思是模块。
  • 为什么在路由器中初始化套接字。 Socket和Router不同 第一次调用get route方法时,第一次创建socket对象,再次调用时又创建了另一个对象,也就是说,当你调用两次路由时,它创建了两个socket对象。

标签: javascript node.js sockets socket.io


【解决方案1】:

您可以通过控制台记录io.sockets来查看记录的事件监听器

Namespace {
  _events:
   { connection: [ [Function], [Function], [Function], [Function] ] },
  _eventsCount: 1 }

要解决您的问题,只需在初始化套接字连接之前设置此条件

  if(io.sockets._events == undefined) {
    io.on('connection', socket => {
      ...
    });
  }

如果除了connection之外还有其他事件监听器

  if(!('connection' in io.sockets._events)) {
    io.on('connection', socket => {
      ...
    });
  }

【讨论】:

    【解决方案2】:

    这里的问题是你把:

     req.app.io.on('connection', function(socket){...}
    

    app.get() 内。这意味着每次命中该路由时,您都会添加另一个 io.on('connection', ...) 处理程序,从而导致重复的事件处理程序。

    您实际上并没有连接太多的套接字,因为重复的事件处理程序,您只是将重复的消息输出到控制台。如果您查看实际连接的套接字数,您会发现实际存在适当的数量。

    您几乎应该永远不要在路由处理程序中安装事件处理程序,因为每次命中该路由时,您都会添加另一个事件处理程序并且重复累积(这通常会导致问题)。

    你没有展示你在这条路线上想要完成的事情,所以我无法为你想要解决的任何问题提供解决方案。您可以将路由外的io.on('connection', ...) 移动到模块的顶层,然后您将在该模块中拥有一个,但不会在每次命中该路由时创建重复的事件处理程序。

    如果您真正想做的是能够向请求此路由的客户端的 socket.io 连接发送消息,那么这是一件更复杂的事情。如果这是一个服务于 HTML 页面的路由(而不是来自已加载页面的 Ajax 调用),因为它是 / 路由,那么您根本无法发送到该页面的 socket.io 连接路由处理程序,因为它是一个新页面,它还没有建立它的 socket.io 连接(哎呀,页面甚至还没有被发送到浏览器)。您无法与尚未连接的事物进行交流。可能,无论您想通过 socket.io 发送什么,您都应该将页面呈现为 Javascript 状态,该页面在首次运行时可以访问,或者包含已经呈现的 HTML 状态。

    【讨论】:

    • 我如何在“app.js”中使用带有reqsessions的Socket.io,因为我想使用之前存储的req.sessionIDreq.session.memberId。注意:我使用 express-session 我使用了这个函数app.use(function(req,res){ console.log(req.sessionId) }) 它打印会话 ID,但路由器(模块)不呈现。
    • @AliHassan - 我不明白你在那条评论中问了什么。请用文字(和代码)描述您要完成的工作。
    • 我想在会话中使用套接字。
    • @AliHassan - 好吧,到目前为止,你的问题并没有说明什么。而且,您根本没有在使用会话的问题中显示任何代码。也许这就是你想要的:express-socket.io-session.
    • @jfrienf00 - 谢谢 :)
    【解决方案3】:

    当您连接服务器时,您可以将此信息保存在 localStorage 中。刷新后检查元素是否在 localStorage 中可用,如果它是错误的,则将信息发送到新用户连接的服务器。

    【讨论】:

    • 我更新了问题 .. 在 app.js 文件中我使用 ** io.on('connetion') ** 并且当客户端刷新时它只连接一次。 ** router.get('/') ** 的问题并在每次刷新时导出路由器。我无法解决这个问题-_-
    • 这个答案不是导致 OP 问题的原因。