WebSocket: How to automatically reconnect after it dies

var ws = new WebSocket('ws://localhost:8080');
ws.onopen = function () {
ws.send(JSON.stringify({
.... some message the I must send when I connect ....
}));


};


ws.onmessage = function (e) {
console.log('Got a message')
console.log(e.data);
};


ws.onclose = function(e) {
console.log('socket closed try again');


}


ws.onerror = function(err) {
console.error(err)
};

When I first connect to the socket, I must first send a message to the server to authenticate myself and subscribe to channels.

The problem I have is that sometimes the socket server is unreliable and that triggers the onerror and onclose events of the 'ws' object.

Question: What is a good design pattern that would allow me, whenever the socket closes or encounters an error, wait for 10 seconds and then reconnect to the socket server (and resend the initial message to the server)

187254 次浏览

这就是我最后得到的,对我有用。

function connect() {
var ws = new WebSocket('ws://localhost:8080');
ws.onopen = function() {
// subscribe to some channels
ws.send(JSON.stringify({
//.... some message the I must send when I connect ....
}));
};


ws.onmessage = function(e) {
console.log('Message:', e.data);
};


ws.onclose = function(e) {
console.log('Socket is closed. Reconnect will be attempted in 1 second.', e.reason);
setTimeout(function() {
connect();
}, 1000);
};


ws.onerror = function(err) {
console.error('Socket encountered error: ', err.message, 'Closing socket');
ws.close();
};
}


connect();

更新答案:

最后,(如果你不使用 java)我发现你最好实现你自己的“乒乓”策略。(如果你正在使用 java,请看一下乒乓球的“动作类型”,我记不太清楚了...)

  1. 客户端每5秒向服务器发送一次“ ping”。
  2. 服务器一旦接收到“ ping”,就应该向客户端回应一个“ pong”。
  3. 客户端应重新连接服务器,如果没有收到“乒乓”在5秒钟。

不要依赖任何第三方的谎言。

警告: 不要使用这些工具: (原因: 它们不可靠,不稳定,工作方式非常有限。)

  1. 检查网络是否可用: https://github.com/hubspot/offline
  2. 重新连接: https://github.com/joewalnes/reconnecting-websocket

这对我的 setInterval工作,因为客户端连接可能会丢失。

ngOnInit(): void {
if (window.location.protocol.includes('https')) {
this.protocol = 'wss';
}


this.listenChanges();
}




listenChanges(): void {
this.socket = new WebSocket(`${this.protocol}://${window.location.host}/v1.0/your/url`);


this.socket.onmessage = (event): void => {
// your subscription stuff
this.store.dispatch(someAction);
};


this.socket.onerror = (): void => {
this.socket.close();
};




this.socket.onopen = (): void => {
clearInterval(this.timerId);


this.socket.onclose = (): void => {
this.timerId = setInterval(() => {
this.listenChanges();
}, 10000);
};
};
}

打开套接字后,不要忘记调用 clearInterval

我发现这个包 https://github.com/pladaria/reconnecting-websocket可以解决 Websocket 连接的重连接问题。它有一系列可配置的选项,其中之一就是 reconnectionDelayGrowFactor,它决定了重连延迟的增长速度。

使用异步-等待,如果套接字关闭或任何错误发生在服务器上,客户端将尝试自动连接每5秒钟,永远 看看我的答案

这并不是一个明确的反应式问题,但这里有一个反应式答案:

TLDR: 您可以使用 setInterval定期检查 websocket 连接状态,并在连接关闭时尝试重新连接。< a href = “ https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState”rel = “ norefrer”> https://developer.mozilla.org/en-us/docs/web/api/websocket/readystate

class TestComponent extends React.Component {
constructor(props) {
super(props);
this.state = {};


this.connect = this.connect.bind(this);
}


componentDidMount() {
this.interval = setInterval(this.connect, 1000);
}


componentWillUnmount() {
if (this.ws) this.ws.close();
if (this.interval) clearInterval(this.interval);
}


connect() {
// https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState
if (this.ws === undefined || (this.ws && this.ws.readyState === 3)) {
this.ws = new WebSocket(`ws://localhost:8080`);


this.ws.onmessage = (e) => {
console.log(JSON.parse(e.data));
};
}
}


render() {
return <div>Hey!</div>;
}
}

你可以使用一个 小图书馆,如果你想-重新连接 WebSocket

在脚本标记中添加 重新连接-websocket. js,然后

它是兼容 API 的,所以当你有:

var ws = new WebSocket('ws://....');

你可以用以下代替:

var ws = new ReconnectingWebSocket('ws://....');

试试这个:

const observable = Observable.create(
(obs: Observer<MessageEvent>) => {
this.ws.onmessage = obs.next.bind(obs);
this.ws.onerror = obs.error.bind(obs);
// this.ws.onclose = obs.complete.bind(obs);
this.ws.onclose = function () {
window.location.reload()
}
return this.ws.close.bind(this.ws);
});


const observer = {
next: (data: Object) => {
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(data));
}
}
};

组件

getDatas() {
let url = environment.apiwebsocket
this.webSocketService.connect(url)
.subscribe(evt => {
let jsonObj = JSON.parse(evt.data)
});}

我曾经在项目中的某个地方有这个:

let rc = new WebSocket(
'ws://'
+ window.location.host
+ `/ws/chat/${window.seen.pk}/`
)

现在我换到:

// ws create the websocket and returns it
function autoReconnect(ws_create){
let ws = ws_create();
function startReconnecting(){
let interval = setInterval(()=>{
console.log('trying')
ws = ws_create();
ws.onopen = () => {
console.log('stop');
ws.onclose = startReconnecting;
clearInterval(interval);
}
}, 3000);
}
ws.onclose = startReconnecting;
}


let rc;
autoReconnect(()=>{
rc = new WebSocket(
'ws://'
+ window.location.host
+ `/ws/chat/${window.seen.pk}/`
)
return rc;
});

通过运行并停止本地主机来测试它,它工作正常。(顺便说一下,我发现这个问题已经发布了很长时间,但没有一个简短和优雅的解决方案)很奇怪

这个方法的好处是,它允许您传入一个箭头函数,这样您就可以将变量赋给任何外部作用域。

Socket.io 提供了这个特性

在客户端指示 reconnection: true

 const io = require("socket.io-client");
const socket = io('ws://'+WS_REMOTE_ADDRESS,{
reconnection: true,
});