[英]WebSocket Connection timeout
我正在嘗試實現failafe websocket包裝器。 而我遇到的問題是處理超時錯誤。 邏輯應該是:如果套接字在$ timeoutInMiliseconds期間沒有打開 - 它必須關閉並重新打開$ N次。
我寫的是這樣的。
var maxReconects = 0;
var ws = new WebSocket(url);
var onCloseHandler = function() {
if ( maxReconects < N ) {
maxReconects++;
// construct new Websocket
....
}
};
ws.onclose = onCloseHandler;
var timeout = setTimeout(function() {
console.log("Socket connection timeout",ws.readyState);
timedOut = true;
ws.close(); <--- ws.readyState is 0 here
timedOut = false;
},timeoutInMiliseconds);
但問題是正確處理超時websockets - 如果我試圖關閉未連接的套接字我在chrome中收到警告:
“與'ws://127.0.0.1:9010 / timeout'的WebSocket連接失敗:在建立連接之前WebSocket已關閉。”
我不知道如何避免它 - ws接口沒有中止功能。
我嘗試過的另一個方法是在超時時關閉套接字,如果它沒有連接,只是將其標記為不使用更多並關閉它,如果它接收到readyState多於一個 - 但它可能產生可能的泄漏,並且復雜的這樣簡單的任務。
你的timeout
變量被分配給setTimeout(...
函數,它正在被詞法調用。當你的代碼到var onCloseHander = ...
你的timeout
函數已被調用。
解決這個問題的方法是創建一個makeTimeout
函數:
var makeTimeout = function (timeoutInMiliseconds) {
return window.setTimeout(function() {
// do stuff
}, timeoutInMiliseconds)
};
var timeoutId = makeTimeout(100)
將調用setTimeout
函數並將timeoutId
設置為超時ID的值。 如果需要取消此超時,可以通過調用window.clearTimeout(timeoutId)
來完成。
我已經編寫了以下代碼來打開帶有超時和重試的websocket failafe ,有關更多詳細信息,請參閱代碼中的注釋。
用法 - 打開一個5000毫秒超時和10次重試(最大)的websocket:
initWebsocket('ws:\\localhost:8090', null, 5000, 10).then(function(socket){
console.log('socket initialized!');
//do something with socket...
//if you want to use the socket later again and assure that it is still open:
initWebsocket('ws:\\localhost:8090', socket, 5000, 10).then(function(socket){
//if socket is still open, you are using the same "socket" object here
//if socket was closed, you are using a new opened "socket" object
}
}, function(){
console.log('init of socket failed!');
});
方法initWebsocket()
在庫或類似的地方定義:
/**
* inits a websocket by a given url, returned promise resolves with initialized websocket, rejects after failure/timeout.
*
* @param url the websocket url to init
* @param existingWebsocket if passed and this passed websocket is already open, this existingWebsocket is resolved, no additional websocket is opened
* @param timeoutMs the timeout in milliseconds for opening the websocket
* @param numberOfRetries the number of times initializing the socket should be retried, if not specified or 0, no retries are made
* and a failure/timeout causes rejection of the returned promise
* @return {Promise}
*/
function initWebsocket(url, existingWebsocket, timeoutMs, numberOfRetries) {
timeoutMs = timeoutMs ? timeoutMs : 1500;
numberOfRetries = numberOfRetries ? numberOfRetries : 0;
var hasReturned = false;
var promise = new Promise((resolve, reject) => {
setTimeout(function () {
if(!hasReturned) {
console.info('opening websocket timed out: ' + url);
rejectInternal();
}
}, timeoutMs);
if (!existingWebsocket || existingWebsocket.readyState != existingWebsocket.OPEN) {
if (existingWebsocket) {
existingWebsocket.close();
}
var websocket = new WebSocket(url);
websocket.onopen = function () {
if(hasReturned) {
websocket.close();
} else {
console.info('websocket to opened! url: ' + url);
resolve(websocket);
}
};
websocket.onclose = function () {
console.info('websocket closed! url: ' + url);
rejectInternal();
};
websocket.onerror = function () {
console.info('websocket error! url: ' + url);
rejectInternal();
};
} else {
resolve(existingWebsocket);
}
function rejectInternal() {
if(numberOfRetries <= 0) {
reject();
} else if(!hasReturned) {
hasReturned = true;
console.info('retrying connection to websocket! url: ' + url + ', remaining retries: ' + (numberOfRetries-1));
initWebsocket(url, null, timeoutMs, numberOfRetries-1).then(resolve, reject);
}
}
});
promise.then(function () {hasReturned = true;}, function () {hasReturned = true;});
return promise;
};
更好的解決方案是將功能封裝在自己的類FailsafeWebsocket
或者無論如何。 然而,這個解決方案在我的項目中已經足夠了 - 也許它對其他人也有幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.