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
和断开连接时,delete
比 splice
更简单: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 在具有相同令牌的用户之间发送消息?
AWS WebSocket API 网关必须对 $connect、$disconnect 和 $default 具有相同的集成?