websocket 在客户端上刷新页面后恢复与套接字的连接

6yoyoihd  于 2021-06-24  发布在  其他
关注(0)|答案(1)|浏览(184)

**我想要的:**我使用node js。目前我的项目没有任何逻辑,但我需要了解套接字是如何工作的。我在客户端有一个任务列表,在那里我输入任务的名称,重复时间和任务停止的时间。我需要在客户端和服务器上都显示日志。例如,如果用户输入:“任务1”每2分钟重复一次,一小时完成

然后在服务器和客户端上的浏览器控制台中显示:

| "Task 1" started at 11:00 AM   |
| Completed task "Task 1" at 11:02 AM   |
| Started task "Task 1" at 11:02 AM   |
| Completed task "Task 1" at 11:04 AM   |
| ...  |
| ...  |
| Completed Task 1 task after the time at 12:00 AM  |

字符串

**问题是什么:**我已经做了所有的事情,但是问题仍然存在,如果你刷新网站页面,到套接字的连接会断开,并创建一个新的连接。这会导致新的“任务已启动”和“任务已完成”消息不会显示在浏览器控制台中。
**我想做的是:**我找到了一个official article on my problem。我似乎已经做了所有需要做的事情,但没有帮助。刷新页面仍然会建立新的连接。控制台中不显示新消息。
**我的代码:**server.js

const server = http.createServer(app);
const io = socketIO(server, {
  connectionStateRecovery: {
    maxDisconnectionDuration: 2 * 60 * 1000,
    skipMiddlewares: true,
  }
});

io.on('connection', (socket) => {
  if (socket.recovered) {
    console.log('Соединение восстановлено:', socket.id);
    // Восстановление состояния сокета
    // Ваш код для обработки восстановленного состояния сокета
  } else {
    console.log('Новое подключение:', socket.id);
    // Ваш код для нового подключения
  }
  

  // Обработчик запуска задачи
  socket.on('startTask', (data) => {
    const { duration, stopAfter, nameTask, userId } = data;

    // Проверка, есть ли уже активная задача для данного пользователя
    if (userTasks[userId]) {
      socket.emit('taskError', { message: `У вас уже есть активная задача ${userTasks[userId]}` });
      console.log(`У вас уже есть активная задача`);
      console.log(userTasks);
      return;
    }
    // Проверка, есть ли уже задача с таким именем для данного пользователя
    if (userTasks[userId] && userTasks[userId][nameTask]) {
      socket.emit('taskError', { message: 'Не возможно запустить ещё одну задачу' });
      return;
    }
    

    const task = {
      id: taskId,
      duration,
      stopAfter,
      nameTask,
      userId,
      startTime: moment(),
      stopTime: moment().add(stopAfter, 'hours'),
    };

    // Добавление задачи в соответствующую структуру данных
    if (!userTasks[userId]) {
      userTasks[userId] = {};
    }
    userTasks[userId][nameTask] = task;
    taskId++;

    console.log(`Задача с id ${task.id} запущена ${new Date()}`);
    console.log(userTasks);
    // Отправка сообщения клиенту о запуске задачи
    socket.emit('taskStarted', task);

    // Запуск цикла задачи
    const taskInterval = setInterval(() => {
      const currentTime = moment();

      if (currentTime.isBefore(task.stopTime)) {
        console.log(`Задача с id ${task.id} завершена ${new Date()}`);
        socket.emit('taskStarted', task);

        console.log(`Задача с id ${task.id} запущена ${new Date()}`);
        socket.emit('taskCompleted', task);
      } else {
        console.log(`Задача с id ${task.id} завершена по истечению времени ${new Date()}`);
        clearInterval(taskInterval);
        delete userTasks[userId];
        socket.emit('taskFinished', task);
      }
    }, duration * 60000);

    // Обработчик остановки задачи
    socket.on('stopTask', (taskId) => {
      // Удаление задачи из соответствующей структуры данных
      if (userTasks[userId] && userTasks[userId][nameTask]) {
        console.log(`Задача с id ${taskId} завершена принудительно ${new Date()}`);
        clearInterval(taskInterval);
        delete userTasks[userId];
        socket.emit('taskForceStopped', taskId);
      }
    });
  });

  // Обработчик отключения клиента
  socket.on('disconnect', () => {
    console.log('Клиент отключился:', socket.id);
    // Получение userId из объекта socket
    const user = Object.keys(socket.rooms).find((room) => room !== socket.id);
    // Удаление информации о задачах пользователя при отключении
    if (userTasks[user]) {
      delete userTasks[user];
    }
  
    // Поиск и удаление соединения из хранилища по идентификатору пользователя
    const userId = Object.keys(userSockets).find((key) => userSockets[key] === socket);
    if (userId) {
      console.log(`Соединение ${socket.id} удалено из хранилища для пользователя ${userId}`);
    }
   
  });
  
});


index.html:

// Подключение к серверу WebSocket с сохраненным userId
    socket.on('connect', () => {
      console.log('Подключено к серверу WebSocket');
      if (socket.recovered) {
        console.log('Соединение восстановлено:', socket.id);
        // Восстановление состояния сокета
        // Ваш код для обработки восстановленного состояния сокета
      } else {
        console.log('Новое подключение:', socket.id);
        // Ваш код для нового подключения
      }

      console.log("recovered?", socket.recovered);
/*
      setTimeout(() => {
        if (socket.io.engine) {
          // close the low-level connection and trigger a reconnection
          socket.io.engine.close();
        }
      }, 10000);*/
    });

    // Попытка восстановить соединение при обновлении страницы
    if (socket.connected) {
      console.log('Connection already established');
    } else {
      console.log('Attempting to reconnect');
      socket.connect();
    }
    // Обработчик запуска задачи
    function startTask(taskId) {
      const duration = document.getElementById(`duration${taskId}`).value;
      const stopAfter = document.getElementById(`stopAfter${taskId}`).value;
      const nameTask = document.getElementById(`nameTask${taskId}`).value;
      //const userId = document.getElementById('userId').value;

      socket.emit('startTask', {
        duration,
        stopAfter,
        nameTask,
        userId
      });
    }

    // Обработчик остановки задачи
    function stopTask(taskId) {
      socket.emit('stopTask', taskId);
    }

    // Обработчик запуска задачи на сервере
    socket.on('taskStarted', (task) => {
      console.log(`Задача с id ${task.id} запущена ${new Date()}`);

    });

    // Обработчик завершения задачи на сервере
    socket.on('taskCompleted', (task) => {
      console.log(`Задача с id ${task.id} завершена ${new Date()}`);
    });

    // Обработчик завершения задачи по истечению времени на сервере
    socket.on('taskFinished', (task) => {
      console.log(`Задача с id ${task.id} завершена по истечению времени ${new Date()}`);
    });

    // Обработчик принудительной остановки задачи на сервере
    socket.on('taskForceStopped', (taskId) => {
      console.log(`Задача с id ${taskId} завершена принудительно ${new Date()}`);
    });

    // Обработчик ошибки запуска задачи на сервере
    socket.on('taskError', (error) => {
      console.log('Ошибка запуска задачи:', error.message, ' ${new Date()}');
    });


请帮我在刷新页面后重新连接socket或者其他方式在浏览器控制台输出新消息。对不起我的英语。完整代码:https://drive.google.com/file/d/1-AyA8UPqRpALAkjH-A9wDkkIstD3v2n9/view?usp=drive_link

weylhg0b

weylhg0b1#

如果你真的想支持这样的东西,你需要开始考虑更多的异步。你不能在startTask中完成所有的工作,因为只要你emit到一个关闭的套接字,它就会停止。
您需要服务器有一个全局任务队列,独立于任何连接。当一个“开始”进来时,它会向队列添加一些东西,一些主“任务执行者”开始处理任务,独立于套接字。您需要让客户端提交某种标识,类似于HTTP cookie,否则服务器根本无法判断传入的连接是新会话还是旧会话的恢复。一旦你有了它,你就可以有一个“状态”提要,它从全局任务队列中读取状态。
如果你要支持这一点,你需要为每个emit失败做好准备,因为如果浏览器刷新,就会发生这种情况。总而言之,最好的解决方案可能是用大红字警告用户不要刷新。

相关问题