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