websockets - 检测具有相同ID的多个客户端并“踢”它们

时间:2016-03-10 13:23:54

标签: javascript websocket

这是我的服务器端websocket脚本:

var clients = [ ];

//sample request: ****:8080/?steamid=123456789
var connection;
var aqsteamid = getParameterByName("steamid",request.resource);

connection = request.accept(null, request.origin); 

connection.ID = aqsteamid;
connection.balRefreshes = 0;
connection.clientIndex = clients.push(connection) - 1;

//check if this user is already connected. If yes, kicks the previous client ***====EDITED====***
for(var i = 0; i < clients.length; i++)
{
    if(clients[i].ID === aqsteamid){
        var indx = clients.indexOf(clients[i]);
        clients[indx].close();
    }
}

console.log('ID',connection.ID,' connected.');


socket.on('close', function(webSocketConnection, closeReason, description){
    try{
        console.log('ID',webSocketConnection.ID,'disconnected. ('+closeReason+';'+description+')');
        webSocketConnection.balRefreshes = 0;
        webSocketConnection.spamcheck = false;
        clients.splice(webSocketConnection.clientIndex, 1);
    }catch(e)
    {
        console.log(e);
    }
});

基本上我想要的是使用相同的ID启动所有连接(例如,连接多个浏览器选项卡)。

但是,它不是踢旧客户端,而是踢两个客户端,或者在某些情况下两个客户端都保持连接相同的ID。

我的剧本中是否有其他方式或有任何错误?

由于

2 个答案:

答案 0 :(得分:1)

使用Array的对象instad来键入clients池,使其更快更简单:

var clients = {};

//sample request: ****:8080/?steamid=123456789
var connection;
var aqsteamid = getParameterByName("steamid",request.resource);

connection = request.accept(null, request.origin); 

connection.ID = aqsteamid;
connection.balRefreshes = 0;
clients[aqsteamid]=connection;

socket.on('close', function(webSocketConnection, closeReason, description){
    try{
        console.log('ID',webSocketConnection.ID,'disconnected. ('+closeReason+';'+description+')');
        webSocketConnection.balRefreshes = 0;
        webSocketConnection.spamcheck = false;
        delete clients[aqsteamid];
    }catch(e)
    {
        console.log(e);
    }
});

//check if this user is already connected. If yes, kicks the previous client 
if(clients[aqsteamid]) clients[aqsteamid].close();
console.log('ID',connection.ID,' connected.');

使用对象池,我们可以删除所有数组池循环和比较逻辑,我们的索引永远不会失去同步。

答案 1 :(得分:0)

听起来多个具有相同ID的连接可能是具有多个标签的真正工作流程的一部分(不像是,恶意用户故意用多个线程抓取数据......)

而不是&#34;踢&#34;来自其他标签的用户然后必须处理它们重新连接,一个更优雅的解决方案是在多个标签中引入业务流程层。

您可以依靠localstorage api选择一个主标签来处理与服务器的通信(如果它的websocket或ajax并不重要)并与其他标签共享响应 - 再次通过localstorage 。如果您在共享数据时打开1或20个选项卡并不重要,因为您关心相同的邮件通知或股票代码更新等等。

来自another stackoverflow answer

  

storage事件允许您在标签之间传播数据,同时保持一个   单个SignalR连接打开(从而防止连接   饱和)。致电localStorage.setItem('sharedKey', sharedData)   将在所有其他选项卡(而不是调用者)中引发storage事件:

$(window).bind('storage', function (e) {
    var sharedData = localStorage.getItem('sharedKey');
    if (sharedData !== null)
        console.log(
            'A tab called localStorage.setItem("sharedData",'+sharedData+')'
        );
});

根据上面的代码,如果在加载页面时已经有sharedKey值,则假设主选项卡处于活动状态并从localstorage获取共享值。您可以检查是否需要重新选举主选项卡(即,浏览器选项卡已关闭或导航),间隔或依赖于page visibility api等更复杂的内容。

请注意,您不仅限于分享&#34;相同&#34;跨多个标签的数据,而是通过共享渠道批量处理任何请求。