php 服务器在 WebSocket 中重新启动时重新连接客户端
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3780511/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Reconnection of Client when server reboots in WebSocket
提问by siddhusingh
I am using web socket using PHP5 and the Chrome browser as client. I have taken the code from the site http://code.google.com/p/phpwebsocket/.
我正在使用使用 PHP5 和 Chrome 浏览器作为客户端的网络套接字。我从网站http://code.google.com/p/phpwebsocket/获取了代码。
I run the server, and the client is also connected. I can chat as well. Now when I restart the server (by killing it and starting it again), the client gets the disconnected information, but automatically doesn't reconnect with server when I send the message.
我运行服务器,客户端也连接上了。我也可以聊天。现在,当我重新启动服务器(通过杀死它并重新启动它)时,客户端获取断开连接的信息,但在我发送消息时不会自动重新连接服务器。
How to achieve this? Like when I get the dis-connected information, should I check it and send it to JavaScript to refresh the page or reconnect?
如何实现这一目标?就像当我收到断开连接的信息时,我应该检查它并将其发送给 JavaScript 以刷新页面还是重新连接?
回答by Andrew
When the server reboots, the Web Socket connection is closed, so the JavaScript onclose
event is triggered. Here's an example that tries to reconnect every five seconds.
当服务器重新启动时,Web Socket 连接关闭,因此onclose
触发JavaScript事件。这是一个尝试每五秒重新连接一次的示例。
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);
};
}
回答by user2909737
The solution given by Andrew isn't perfectly working because, in case of lost connection, the server might send several close events.
Andrew 给出的解决方案并不完美,因为在连接丢失的情况下,服务器可能会发送多个关闭事件。
In that case, you'll set several setTimout's. The solution given by Andrew may only work if the server is ready before five seconds.
在这种情况下,您将设置多个 setTimout。Andrew 给出的解决方案可能只有在服务器在 5 秒前准备就绪时才有效。
Then, based on Andrew solution, reworked, I've made use of setInterval attaching the ID to the window object (that way it is available "everywhere"):
然后,基于 Andrew 解决方案,重新设计,我利用 setInterval 将 ID 附加到 window 对象(这样它在“任何地方”都可用):
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 */
/* ... */
}
回答by Jo?l Esponde
ReconnectingWebSocket
重新连接WebSocket
GitHub hosts a small JavaScript library that decorates the WebSocket API to provide a WebSocket connection that will automatically reconnect if the connection is dropped.
GitHub 托管了一个小型 JavaScript 库,该库修饰 WebSocket API 以提供 WebSocket 连接,如果连接断开,该连接将自动重新连接。
Minified library with gzip compression is less than 600 bytes.
使用 gzip 压缩的缩小库小于 600 字节。
The official repository is available here:
官方存储库可在此处获得:
https://github.com/joewalnes/reconnecting-websocket
https://github.com/joewalnes/reconnecting-websocket
Server flood
服务器泛滥
If a high number of clients are connected to the server when it reboots. It may be worthwhile to manage the reconnect timings of the clients by using an Exponential Backoff algorithm.
如果服务器重新启动时有大量客户端连接到服务器。使用指数退避算法管理客户端的重新连接时间可能是值得的。
The algorithm works like this:
该算法的工作原理如下:
- For k attempts, generate a random interval of time between 0 and 2^k - 1,
- If you are able to reconnect, reset k to 1,
- If reconnection fails, k increases by 1 and the process restarts at step 1,
- To truncate the max interval, when a certain number of attempts k has been reached, k stops increasing after each attempt.
- 对于 k 次尝试,生成 0 到 2^k - 1 之间的随机时间间隔,
- 如果您能够重新连接,请将 k 重置为 1,
- 如果重新连接失败,k 增加 1,进程从步骤 1 重新开始,
- 为了截断最大间隔,当达到一定的尝试次数 k 时,k 在每次尝试后停止增加。
Référence:
参考:
http://blog.johnryding.com/post/78544969349/how-to-reconnect-web-sockets-in-a-realtime-web-app
http://blog.johnryding.com/post/78544969349/how-to-reconnect-web-sockets-in-a-realtime-web-app
ReconnectingWebSocket does not handle reconnections by using this algorithm.
ReconnectingWebSocket 不使用此算法处理重新连接。
回答by complistic
I have been using this patten for a while for pure vanilla JavaScript, and it supports a few more cases than the other answers.
我已经将这种模式用于纯香草 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);
});
This will retry as soon as the server closes the connection, and it will check the connection to make sure it's up every 5 seconds also.
一旦服务器关闭连接,这将重试,并且它会检查连接以确保它每 5 秒也启动一次。
So if the server is not up when this runs or at the time of the onclose event the connection will still come back once it's back online.
因此,如果服务器在此运行时或在 onclose 事件发生时未启动,则一旦重新联机,连接仍将返回。
NOTE: Using this script will not allow you to ever stop trying to open a connection... but I think that's what you want?
注意:使用此脚本不会让您停止尝试打开连接...但我认为这就是您想要的?
回答by Pradeepta
Below are the codes i have used in my project which working 100%.
以下是我在我的项目中使用的代码,它们 100% 工作。
- Put all the websocket code inside the init function.
- Inside the onclose callback call the init again.
- Finally call the init function inside the document ready function.
- 将所有 websocket 代码放在 init 函数中。
- 在 onclose 回调中再次调用 init。
- 最后在文档就绪函数中调用 init 函数。
var name = sessionStorage.getItem('name');
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(); };
}
回答by xemasiv
Can't comment, but the following:
无法评论,但以下内容:
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);
Plus https://www.npmjs.com/package/backis already good enough :)
加上https://www.npmjs.com/package/back已经足够好了 :)
回答by Zibri
function wsConnection(url){
var ws = new WebSocket(url);
var s = (l)=>console.log(l);
ws.onopen = m=>s(" CONNECTED")
ws.onmessage = m=>s(" RECEIVED: "+JSON.parse(m.data))
ws.onerror = e=>s(" ERROR")
ws.onclose = e=>{
s(" CONNECTION CLOSED");
setTimeout((function() {
var ws2 = new WebSocket(ws.url);
ws2.onopen=ws.onopen;
ws2.onmessage = ws.onmessage;
ws2.onclose = ws.onclose;
ws2.onerror = ws.onerror;
ws = ws2
}
).bind(this), 5000)
}
var f = m=>ws.send(JSON.stringify(m)) || "Sent: "+m;
f.ping = ()=>ws.send(JSON.stringify("ping"));
f.close = ()=>ws.close();
return f
}
c=new wsConnection('wss://echo.websocket.org');
setTimeout(()=>c("Hello world...orld...orld..orld...d"),5000);
setTimeout(()=>c.close(),10000);
setTimeout(()=>c("I am still alive!"),20000);
<pre>
This code will create a websocket which will
reconnect automatically after 5 seconds from disconnection.
An automatic disconnection is simulated after 10 seconds.
回答by Waket Zheng
Finally, I make ws auto reconnect in vue+ts, similar as following:
最后,我在vue+ts中让ws自动重连,类似如下:
private async mounted() {
// Connect to WebSocket
const sn = "sb1234567890";
const host =
window.location.protocol == "https:"
? "wss://www.xxx.net"
: process.env.DEV_TYPE === "fullstack"
? "ws://10.0.0.14:8528"
: "ws://www.xxx.net:8528";
const wsUri = host + "/feed-home/" + sn;
await this.startWs(wsUri, sn);
// !!!Deprecated: failed to reconnect
// let ws = new WebSocket();
// console.log(ws);
// ws.onopen = async function(event) {
// console.log(event, "openEvent");
// clearInterval(that.timer);
// };
// ws.onclose = async function(event) {
// console.log(event, "close");
// that.timer = setInterval(() => {
// console.log("Heart Beat");
// ws.send("HeartBeat");
// // ws = new WebSocket("ws://10.0.0.14:8528/feed-home/" + sn);
// console.log(ws);
// }, 60000);
// };
// ws.onmessage = async function(event) {
// console.log(event, "ws");
// alert("get it!");
// await alert("please update!");
// await that.getHome(sn);
// };
}
private wsReconnected: boolean = false; // check whether WebSocket is reconnected
private async startWs(uri: string, sn: string) {
let that = this;
let ws = new WebSocket(uri);
ws.onopen = async () => {
if (that.wsReconnected) {
await that.getHome(sn); // Refresh api data after reconnected
}
ws.send("Current client version: " + window.version);
};
ws.onmessage = async evt => {
await that.getHome(sn);
that.$message({
type: "success",
message: evt.data,
showClose: true,
center: true,
duration: 20 * 1000
});
};
ws.onclose = async () => {
that.wsReconnected = true;
await that.startWs(uri, sn);
const sleep = (seconds: number) => {
return new Promise(resolve =>
setTimeout(resolve, seconds * 1000)
);
};
await sleep(10); // Try to reconnect in 10 seconds
// !!!Deprecated: Use timer will cause multiply ws connections
// if (!that.wsTimer) {
// // Try to reconnect in 10 seconds
// that.wsTimer = setInterval(async () => {
// console.log("reconnecting websocket...");
// await that.startWs(uri, sn);
// }, 10 * 1000);
// }
};
}