【问题标题】:Socket.io double events, solved for connect BUT not disconnectSocket.io 双事件,解决连接但不断开连接
【发布时间】:2021-01-28 01:27:40
【问题描述】:

我是 socket.io 和 next.JS 的新手。在将 socket.io 集成到 Next 后,我​​注意到连接代码触发了两次,使我的连接数翻了一番(我需要准确)。

我搜索了很多,但没有找到有效的解决方案,包括 socket.once('connect')。我通过创建 ma​​nual 连接事件并在启动时从客户端发出来解决此问题。只要没有人断开连接,我现在就可以看到准确的连接计数。

至于断开连接,我遇到了同样的问题,每个用户会触发两次断开连接,但我不知道在发生断开连接时如何在客户端手动发出。

关于如何从客户端发出手动断开连接的任何建议?

还是一种新方法?也许使用一个集合来保存客户端 ID 而不是增加一个 int?但是,重复收集计数可能对性能不利(每个用户将非常频繁地访问总计数,可能每秒一次)。

服务器代码

const SERVER_STATE = {
  totalConnections: 0
} 

// socket.io server
io.on('connection', socket => {

  socket.once('userConnectOnce', () => {
    SERVER_STATE.totalConnections++;
    socket.emit('message', `Welcome from server. There are a total of ${SERVER_STATE.totalConnections} connections.`);
    socket.broadcast.emit('message', `New user joined. There are a total of ${SERVER_STATE.totalConnections} connections.`);
  });

  socket.once('disconnect', () => {       // this fires more than once
    SERVER_STATE.totalConnections--;
    socket.broadcast.emit('message', `Other user disonnected. There are now ${SERVER_STATE.totalConnections} connections.`);
  });

});

客户端代码

const Index = () => {
  const socket = useSocket('message', (data) => {
    console.log(data);
  });

  socket.emit('userConnectOnce', 'client-initiated userConnectOnce');

  return (
    <></>
  );
};

注意:useSocket() 是来自下一个示例 repo 的自定义钩子,用于将 socket.on() 包装在 useEffect() 中并返回套接字。我找不到链接,也不确定它是否相关,但这里有一些代码:

import { useEffect } from 'react';
import io from 'socket.io-client';

const socket = io();

export default function useSocket(eventName, cb) {
  useEffect(() => {
    socket.on(eventName, cb);

    return function socketCleanup() {
      socket.off(eventName, cb);
    }
  }, [eventName, cb]);

  return socket;
}

【问题讨论】:

  • 您是自己制作的useSocket 钩子还是使用socket.io 的useSocket 钩子?可以发一下代码吗?
  • 它来自下一个示例存储库。我找不到链接,所以我在上面的代码中添加了。

标签: reactjs socket.io next.js


【解决方案1】:

如果您的Index 组件多次渲染,使用套接字挂钩将再次运行。正如您在 useSocket 钩子中看到的那样,useEffect 依赖于 cb,并且每次运行 Index 组件时,您都会创建新的 callback

【讨论】:

  • 我使用的是 Next.JS,所以 Index.js 是一个页面。其基于文件的路由。在我自己的代码中没有任何地方使用 Index 作为组件——它就在 Next 的底层。但是,我在 Index 声明中添加了一个控制台日志,我注意到了两件事。 1)客户将其注销两次,所以你是对的。我只是还不明白怎么做。 2)我的手动连接事件似乎解决了连接加倍的问题,但实际上这个设置会导致我的总连接在每次页面刷新时减少(单个客户端打开)。啊。至少当我的连接数翻倍时,这并没有发生。有什么想法吗?
  • Index 仍然是一个反应组件,可以渲染任意次数。尝试记忆回调。 reactjs.org/docs/hooks-reference.html#usecallback
  • 我不完全明白在哪里尝试 useCallback 所以我尝试了很多地方都没有成功:从 useSocket 声明返回的回调,useSocket 实现中的 lambda 参数,甚至整个 useSocket 导出函数(哈哈)。诚然,我也不完全理解 useSocket 钩子。但在我看来,useEffect 清理功能中的 socket.off 可能是问题所在。但是,如果我将其注释掉,情况会变得更糟。
  • 我尝试将套接字创建从 useSocket 移动到 Index 并将套接字传递到 useSocket()。增加总连接数。如果可能的话,也许我需要以不涉及计算实际套接字的方式来计算连接数。
【解决方案2】:

我通过重构解决了这个问题,现在它可以工作了。

const SERVER_STATE = {
  users: [ {userId: 123, socketId: 456} ]
} 

我在客户端生成一个带有 UUID 的 userId,并使用 localStorage 保存它。连接时,我将它与 socketId 一起添加到 SERVER_STATE.users,如果它已经存在,我更新 socketId,只是为了确保 socketId 在任何重复调用中保持最新。

在断开连接时,我过滤用户数组。使用 socketId 获取 userId,然后删除具有该 userId 的所有项目。

显然,我需要的总连接数是 users 数组的长度。我可能会将它作为 int 缓存在 SERVER_STATE 中,所以我不需要过多地计算它。

【讨论】:

    猜你喜欢
    • 2013-08-01
    • 2019-05-01
    • 2017-07-17
    • 2014-01-02
    • 2011-11-03
    • 2018-01-28
    • 1970-01-01
    • 2021-04-12
    • 1970-01-01
    相关资源
    最近更新 更多