簡體   English   中英

WebSocket連接超時

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM