关于websocket的重复登陆问题
遇到一个难题是,重复登陆问题,比如A设备登录了,B设备登录了同样的ID,建立了socket连接,这时候A就会收不到消息了(都发到B那里了)。
为了解决这个问题,采用的方法是在B登录时,判断socket连接池里是否已有该id的socket连接,如果有则在B连接之前,先给这个id的socket发送消息,告知已在其他设备登陆,强制退出。
代码比较简单,在OnOpen方法中
if(webSocketSet.get(operatorId) != null && webSocketSet.get(operatorId).session != null){ statusManager.put(operatorId, "repeatLogin"); System.out.println("该操作员已登录,强制退出"); JSONObject result = new JSONObject(); result.put("message", "您已在别处登录,该设备自动退出"); result.put("msgType",MSG_TYPE_REPEAT_LOGIN); result.put("recipientId",operatorId); if(this.OnMessage(result.toString())){ webSocketSet.remove(operatorId); } }
但是这样存在一个问题,A收到强制退出,然后A断开连接了,但是A断开的时候,服务器端的onClose监听到这个A断开了,然后从socket连接池里remove掉这个id,这时候这个id已经是B连接着的了,因为它俩是一样的id,所以把B也带掉了。 于是解决办法是加一个标志位
private static ConcurrentHashMap<String, String> statusManager = new ConcurrentHashMap<>();
当强制登陆的时候,给这个id置为 repeatLogin
statusManager.put(operatorId, "repeatLogin");
如果是正常登录,给这个id置为firstLogin
statusManager.put(operatorId, "firstLogin");
然后在onClose中进行判断
if("firstLogin".equals(statusManager.get(operatorId))){ webSocketSet.remove(this.operatorId); statusManager.remove(this.operatorId); System.out.println("删除成功"); }else{ statusManager.put(this.operatorId,"firstLogin"); }
如果是强制登陆的,也就是B用户,那就啥也不做,不remove,把A用户remove掉
// 服务器响应消息 if (jo.containsKey("senderId") && jo.getString("senderId").equals(this.operatorId)) { try { JSONObject messageResult = new JSONObject(); messageResult.put("msgType", MSG_TYPE_RESPONSE); messageResult.put("type", SEND_MSG_RESULT_TYPE_SUCCESS); messageResult.put("message", "发送成功"); AppointSending(this.operatorId, messageResult.toJSONString()); } catch (Exception e) { // TODO Auto-generated catch block // e1.printStackTrace(); log.error(e.getMessage()); } }