需求是:要求PC和平板建立连接关系,服务器充当转发作用。
功能比较简单,就PC和平板各自脸上socket然后服务器转发消息就是了。
遇到一个难题是,重复登陆问题,比如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掉
Tip:还遇到一个小问题,之前做的功能有一个服务器接收到消息,完成转发后,会给发送端一个回应,其实可以在onMessage中的return中返回就可以,不必要在onMessage代码块中进行主动发送,真是太蠢了。。。
// 服务器响应消息
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());
}
}