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

websockets - detect multiple clients with same ID and "kick" them

本文关键字:客户端 它们 检测 ID websockets      更新时间:2023-09-26

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

还有其他方法还是我的脚本中有任何错误?

谢谢

使用 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.');

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

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

与其将用户从其他选项卡中"踢出",然后不得不处理他们重新连接,更优雅的解决方案是跨多个选项卡引入业务流程层。

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

来自另一个堆栈溢出答案:

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值已经可用,则假设主选项卡处于活动状态并从本地存储获取共享值。您可以检查是否需要重新选择主选项卡(即浏览器选项卡已被关闭或导航离开),并具有间隔或依赖于更复杂的内容,例如页面可见性 api。

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