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

Posted

技术标签:

【中文标题】websockets - 检测具有相同 ID 的多个客户端并“踢”它们【英文标题】:websockets - detect multiple clients with same ID and "kick" them 【发布时间】:2016-03-10 13:23:53 【问题描述】:

这是我的服务器端 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 保持连接。

还有没有其他方法或者我的脚本有什么错误?

谢谢

【问题讨论】:

clients.splice(webSocketConnection.clientIndex, 1); 是问题所在。 splice() 更改了它前面的元素的索引,因此您的 clientIndex 属性与 clients 长时间不一致,这解释了所描述的不稳定症状。您可能需要先使用clients.indexOf() 查找连接的当前索引,然后再使用splice() 顺便说一句,最好使用带有 ID 键的对象,而不是在每个连接事件中循环遍历数组。 used=;.. if(used[aqsteamid])...elseused[aqsteamid]=connection 和断开连接时,deletesplice 更简单:delete used[webSocketConnection.ID]; 嘿,谢谢你的回复。我已经稍微改变了循环,但它仍然是一样的。是否必须使用您的 used=[] 示例来完成? 你只能做一件事,首先检查连接是否存在然后连接,所以没有机会创建另一个具有相同ID的客户端 @dandavis 我忘了在 on('close') 事件中更改脚本,现在似乎工作正常。谢谢,请写一个答案,以便我接受。 【参考方案1】:

使用 Array 的对象来键入 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.');

有了对象池,我们可以去掉所有的数组池循环和比较逻辑,而且我们的索引永远不会不同步。

【讨论】:

【参考方案2】:

听起来具有相同 ID 的多个连接可能是具有多个选项卡的真正工作流程的一部分(例如,恶意用户故意使用多个线程抓取数据......)

与其从其他选项卡“踢”出用户然后不得不处理他们重新连接,更优雅的解决方案是在多个选项卡中引入一个编排层。

您可以依靠 localstorage api 来选择一个主选项卡,该选项卡将处理与服务器的通信(无论是 websocket 还是 ajax 都无关紧要)并与其他选项卡共享响应 - 再次通过 localstorage。当您可以共享这些数据时,您是否打开 1 个或 20 个选项卡并不重要,因为您关心的是相同的消息通知、股票行情更新等。

来自another *** 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 值已经可用,则假设主选项卡处于活动状态并从本地存储中获取共享值。您可以检查是否需要重新选择主选项卡(即该浏览器选项卡已关闭或导航离开),间隔或依赖更复杂的东西,如 page visibility api。

请注意,您不仅限于在多个选项卡之间共享“相同”数据,而是通过共享通道批量处理任何请求。

【讨论】:

以上是关于websockets - 检测具有相同 ID 的多个客户端并“踢”它们的主要内容,如果未能解决你的问题,请参考以下文章

[NodeJS]NodeJS基于WebSocket的多用户点对点即时通讯聊天

基于 websocket 的多端桥接平台

计算机视觉 - 是不是需要具有特定视点的多分类器来进行对象检测?

如何使用 websocket 在具有相同令牌的用户之间发送消息?

AWS WebSocket API 网关必须对 $connect、$disconnect 和 $default 具有相同的集成?

Laravel - 具有关系的多表插入