WebSocket连接超时

时间:2015-04-26 18:48:49

标签: javascript websocket

我正在尝试实现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中收到警告:

&#34; WebSocket连接到&#39; ws://127.0.0.1:9010 / timeout&#39;失败:WebSocket在建立连接之前关闭。&#34;

我不知道如何避免它 - ws接口没有中止功能。

我试过的另一个方法是,如果它没有连接就不要在超时时关闭套接字,只是将它标记为不使用更多,如果接收到readyState不止一个就关闭它 - 但它可能产生可能的泄漏,并且复杂化简单的任务。

2 个答案:

答案 0 :(得分:2)

您的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)来完成。

答案 1 :(得分:2)

我为打开带有超时和重试的websocket failafe编写了以下代码,请参阅代码中的注释以获取更多详细信息。

用法 - 打开一个5000毫秒超时和10次重试(最多)的websocket:

  1: [{"pure_id":"1","branch_id":"45"}]
  2: [{"pure_id":"2","branch_id":"45"}]
  3: [{"pure_id":"3","branch_id":"45"},{"pure_id":"3","branch_id":"45"}]

在库或类似文件中定义的方法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; }; 中,或者无论如何。然而,这个解决方案在我的项目中已经足够了 - 也许它也可以帮助其他人。