Переподключение клиента при перезагрузке сервера в WebSocket
Я использую веб-сокет, используя PHP5 и браузер Chrome как клиент.
Я взял код с сайта http://code.google.com/p/phpwebsocket/.
Я запускаю сервер, и клиент также подключается. Я тоже могу поговорить.
Теперь, когда я перезапускаю сервер (убив его и снова запустив),
клиент получает отключенную информацию, но автоматически не подключается к серверу при отправке сообщения.
Как достичь этого? Например, когда я получаю несвязанную информацию, должен ли я ее проверить и отправить на JavaScript для обновления страницы или повторного подключения?
Ответы
Ответ 1
Когда сервер перезагружается, соединение с веб-сокетом закрывается, поэтому запускается событие JavaScript onclose
. Вот пример, который пытается подключиться каждые пять секунд.
function start(websocketServerLocation){
ws = new WebSocket(websocketServerLocation);
ws.onmessage = function(evt) { alert('message received'); };
ws.onclose = function(){
// Try to reconnect in 5 seconds
setTimeout(function(){start(websocketServerLocation)}, 5000);
};
}
Ответ 2
Решение, данное Andrew, не работает отлично, потому что в случае потерянного соединения сервер может отправить несколько событий закрытия.
В этом случае вы установите несколько setTimout. Решение, данное Эндрю, может работать только в том случае, если сервер готов до пяти секунд.
Затем, на основе решения Andrew, переработанного, я использовал setInterval, прикрепляя идентификатор к объекту окна (таким образом он доступен "везде" ):
var timerID=0;
var socket;
/* Initiate what has to be done */
socket.onopen=function(event){
/* As what was before */
if(window.timerID){ /* a setInterval has been fired */
window.clearInterval(window.timerID);
window.timerID=0;
}
/* ... */
}
socket.onclose=function(event){
/* ... */
if(!window.timerID){ /* Avoid firing a new setInterval, after one has been done */
window.timerID=setInterval(function(){start(websocketServerLocation)}, 5000);
}
/* That way, setInterval will be fired only once after losing connection */
/* ... */
}
Ответ 3
ReconnectingWebSocket
В GitHub размещена небольшая библиотека JavaScript, которая украшает API WebSocket, чтобы обеспечить соединение WebSocket, которое будет автоматически подключаться, если соединение будет удалено.
Мини-библиотека с сжатием gzip меньше 600 байт.
Официальный репозиторий доступен здесь:
https://github.com/joewalnes/reconnecting-websocket
Наводнение сервера
Если при перезагрузке подключено большое количество клиентов к серверу.
Возможно, целесообразно управлять настройками повторного подключения клиентов с помощью алгоритма экспоненциального отказа.
Алгоритм работает следующим образом:
- Для k попыток создайте случайный интервал времени между 0 и 2 ^ k - 1,
- Если вы можете повторно подключиться, reset k к 1,
- Если повторное соединение не выполняется, k увеличивается на 1, и процесс перезапускается на шаге 1,
- Чтобы урезать максимальный интервал, когда достигнуто определенное количество попыток k, k прекращает увеличиваться после каждой попытки.
Справочно:
http://blog.johnryding.com/post/78544969349/how-to-reconnect-web-sockets-in-a-realtime-web-app
ReconnectingWebSocket не обрабатывает пересоединения с использованием этого алгоритма.
Ответ 4
Я использовал этот паттен на некоторое время для чистого ванильного JavaScript, и он поддерживает еще несколько случаев, чем другие ответы.
document.addEventListener("DOMContentLoaded", function() {
'use strict';
var ws = null;
function start(){
ws = new WebSocket("ws://localhost/");
ws.onopen = function(){
console.log('connected!');
};
ws.onmessage = function(e){
console.log(e.data);
};
ws.onclose = function(){
console.log('closed!');
//reconnect now
check();
};
}
function check(){
if(!ws || ws.readyState == 3) start();
}
start();
setInterval(check, 5000);
});
Это повторит попытку, как только сервер закроет соединение, и он проверит соединение, чтобы убедиться, что оно работает каждые 5 секунд.
Итак, если сервер не работает, когда он запускается или во время события onclose, соединение все равно будет возвращаться после его онлайн-подключения.
ПРИМЕЧАНИЕ. Использование этого script не позволит вам перестать пытаться открыть соединение... но я думаю, что вы хотите?
Ответ 5
Ниже приведены коды, которые я использовал в моем проекте, который работает на 100%.
- Поместите весь код websocket внутри функции init.
- Внутри обратного вызова onclose снова вызовите init.
- Наконец, вызовите функцию init внутри функции готовности документа.
var name = sessionStorage.getItem('name');
wsUri = "ws://localhost:8080";
var websocket;
$(function() {
init();
$("#chat_text_box").on("keypress", function(e) {
if (e.keyCode == 13) { //For Enter Button
e.preventDefault();
var mymessage = $('#chat_text_box').val();
if(mymessage){
var msg = { type: 'chat_text', data : { name:name, msg:mymessage } };
console.log(msg);
websocket.send(JSON.stringify(msg));
$('#chat_text_box').val('');
}
return false;
}
});
});
function init() {
websocket = new WebSocket(wsUri);
websocket.onopen = function(ev) { /*connection is open */ }
websocket.onmessage = function(ev) {
var data = JSON.parse(ev.data); //PHP sends Json data
var type = data.type;//alert(JSON.stringify(data));
switch(type) {
case "chat_text":
var text = "<div><span class='user'>"+data.data.sender_name+" : </span><span class='msg'>"+data.data.msg+"</span></div>";
$('#chat-messages').append(text);
break;
default:
break;
}
};
websocket.onerror = function(ev){};
websocket.onclose = function(ev) { init(); };
}
Ответ 6
Невозможно прокомментировать, но следующее:
var socket;
const socketMessageListener = (event) => {
console.log(event.data);
};
const socketOpenListener = (event) => {
console.log('Connected');
socket.send('hello');
};
const socketCloseListener = (event) => {
if (socket) {
console.error('Disconnected.');
}
socket = new WebSocket('ws://localhost:8080');
socket.addEventListener('open', socketOpenListener);
socket.addEventListener('message', socketMessageListener);
socket.addEventListener('close', socketCloseListener);
};
socketCloseListener();
// for testing
setTimeout(()=>{
socket.close();
},5000);
Плюс https://www.npmjs.com/package/back уже достаточно хорош:)