websocket中自动生成身份编号(获取sessionID,将sid值设置为sessionID的方法),并在页面刷新时沿用sid的解决方案

websocket如果需要1对1通信,或者说将服务器数据发送到指定的客户端上,就需要给每一个新生成的websocket加上编号。比较常见的,是在地址映射中加上编号,比如:

@ServerEndpoint(value="/websocket/12")

就代表着编号12的客户端用户。但是这样就需要客户端自行设置一个编号,稍微有些不自然,因此我希望能够自动生成一个编号,并且,我希望他在页面进行刷新时,值不会改变。
因此我选择了用session ID来充当websocket的sid值,session ID是服务器端产生的不会重复的对于连接的一个编号,在进行刷新时,sessionID的值不会改变,但是不会改变也带来了一个新的问题,就是在刷新时,websocket的连接会中断重连,也就是说,将会调用一次onClose以及onOpen,这就会出现一个问题,就是sid值可能会仍旧停留在我最后一次创建客户端时的session值那。这样再进行创建,就很有可能出现sid值的重复了,而且,我刷新以后,我肯定希望是同一个session值作为sid值继续存在,这是基本要求,因此,我需要将这个session值在onOpen时被找到。
说了这么多,先上代码,onOpen的代码:

    //指定的sid,具有唯一性,暫定為用戶的sessionId
    private String sid = "";
    private static String oldsid = "";

    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;
    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
    private static ConcurrentHashMap<String, WebSocketServer> webSocketSet = new ConcurrentHashMap<>();
    public static ArrayList<String>sids=new ArrayList<>();

    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;
    /**
     * 连接建立成功调用的方法*/
    @OnOpen
    public void onOpen(Session session, EndpointConfig config) {
    
    
        //获取WebsocketConfig.java中配置的“sessionId”信息值
//        String httpSessionId = (String) config.getUserProperties().get("sessionId");
        String httpSessionId = MyHttpSessionListener.sessionID;
        System.out.println(oldsid);

        if(!sids.contains(httpSessionId)) {
    
    
        	sids.add(httpSessionId);
        	sid=httpSessionId;
        }else {
    
    
        	sid=oldsid;
        }
        
        this.session = session;
        System.out.println(sid);
        webSocketSet.put(sid,this);     //加入set中
        addOnlineCount();           //在线数加1
        System.out.println("用戶"+sid+"加入!当前在线人数为" + getOnlineCount());
        try {
    
    
            sendMessage("连接成功");
       } catch (IOException e) {
    
    
           log.error("websocket IO异常");
       }
    }

下面是onClose的代码:

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
    
    
    	if(!sid.equals("")) {
    
    
    		System.out.println("用戶"+sid+"退出");
    		oldsid=sid;
            webSocketSet.remove(sid);  //从set中删除
            subOnlineCount();           //在线数减1
            log.info("有一连接关闭!当前在线人数为" + getOnlineCount());
    	}
    }

在onOpen中,创建WebSocketServer,在页面刷新时,会调用onClose,此时,WebSocketServer会销毁,如果此时直接使用sid值,则如果有多个sid值,可能就调用了最近生成的那个新的sid值,这样的话,在创建新的WebSocketServer后,就会出现重复的sid值,就会出错。因此,关键在于怎么不重复创建sid,并且能使得客户端页面刷新前后的sid值不变化。
因此,在调用onClose时,就应该把将要销毁的sid值保存下来,然后再沿用这个sid值进行创建,不然,sid值一旦改变,在程序中调用websocket往前端发送数据时,就可能找不到发送的客户端对象。
因此,我采用sessionid值作为sid,并且将通过HttpSessionListener进行监听。
为了判断是新生成的一个sid值还是刷新生成的sid值,我将所有的sid放入一个arraylist中,放入操作在onOpen中进行,而销毁操作,在session销毁时进行,因此,在做刷新操作时,不会讲原有的sid值去掉
这个时候再判断该sid值是否存在于这个arraylist中,就能判断出是刷新还是新生成的操作。
为了将刷新前的sid值记录下来,我用了一个变量来记录oldsid.
注意,这个oldsid变量的属性必须加上static,不然将无法从onClose将值带到onOpen。
然后是WebSocketServer的代码:

    public static int online = 0;
    public static String sessionID = "";
    Map<String, String> clientip_sessions=  new HashMap<>();
    @Override
    public void sessionCreated(HttpSessionEvent se) {
    
    
        System.out.println("创建session");
        sessionID=se.getSession().getId();
        //设置session永久有效
        se.getSession().setMaxInactiveInterval(-1);
        System.out.println(sessionID);
        online ++;
    }
 
    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
    
    
        System.out.println("销毁session");
        String dsessionID=se.getSession().getId();
        WebSocketServer.sids.remove(dsessionID);
        online --;
    }

上面的代码重点在对于ArrayList的销毁操作上。
另外,在onOpen中有一段我注释掉的代码,也是获取session值的,这一段代码,在调用内部tomcat时可以使用,在部署调用外部tomcat时,就没用了。

String httpSessionId = (String) config.getUserProperties().get("sessionId");

因为,这一段需要依托EndpointConfig,而部署发布的时候,调用外部tomcat,是需要将那一部分注释掉的。

猜你喜欢

转载自blog.csdn.net/baidu_31788709/article/details/104851951
今日推荐