解决WebSocket 服务器 The WebSocket session [0] has been closed and no method...异常信息

来源:互联网 发布:asp.net博客源码 编辑:程序博客网 时间:2024/06/13 04:42
 线程安全的队列来保持所有客户端的Session.
private volatile static List<Session> sessions = Collections.synchronizedList(new ArrayList());private  Session session;    /*     * 客户端链接成功后讲其保存在线程安全的集合中     */    @OnOpen    public void onOpen(Session session) throws IOException {        this.session = session;        sessions.add(this);    } /*     * 客户端断开链接后将其从线程安全的集合中移除     */@OnClose    public void onClose() {        sessions.remove(this);    }    //给所有客户端发送消息public static void sendMessage(String clientInfoJson) {        try {            if (sessions.size() != 0) {                for (session s : sessions) {                    if (s != null) {                       s.getBasicRemote().sendText(clientInfoJson);                    }                }            }        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

上述代码感觉上好像没问题。Session信息是保存在线程安全的集合,又通过volatile变量来修饰保证了内存可见性,但实际运行时却发现并没有想象的那么好。当客户端断开链接,时服务器需要发送消息给客户端时.服务端抛出异常:

IllegalStateException: The WebSocket session [0] has been closed and no method (apart from close()) may be called on a closed session
  • 1
  • 1

不难看出,是服务端在关闭Session即将Session从线程安全的队列移除时,在发送消息的方法里应该被移除的Session消息却进入了发送消息的环节,在执行getBasicRemote().sendText(clientInfoJson);操作时发生了异常。

解决方法:

Google了大量资料后发现如果要解决这种线程安全的问题,不能通过线程安全的集合来保存Session解决。而应该保存整个类,并通过CopyOnWriteArraySet容器来操作。

@ServerEndpoint("/getLocation")@Componentpublic class TransmissionLocationWebSocket {    @Autowired    public TerminalService terminalServiceInWebSocket;    private static CopyOnWriteArraySet<TransmissionLocationWebSocket> sessions = new CopyOnWriteArraySet<TransmissionLocationWebSocket>();    /*     * 线程不安全     */    //private volatile static List<Session> sessions = Collections.synchronizedList(new ArrayList());    private  Session session;    /*     * 链接成功后的回掉     */    @OnOpen    public void onOpen(Session session) throws IOException {        System.out.println("链接成功");        this.session = session;        sessions.add(this);    }    public static void sendUserLocal(String clientInfoJson,) {        try {            if (sessions.size() != 0) {                for (TransmissionLocationWebSocket s : sessions) {                    if (s != null) {                        // 判断是否为终端信息。如果是终端信息则查询数据库获取detail                            s.session.getBasicRemote().sendText(clientInfoJson);                     }            }        }        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }    @OnClose    public void onClose() {        System.out.println("设置离线");        sessions.remove(this);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

完美解决 
备注:虽然我上面贴出来的代码是在COW中保存了整个类,但我测试的时候发生,保存Session也是可以的。

Copy-On-Write简称COW,是一种用于程序设计中的优化策略。其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改,这是一种延时懒惰策略。从JDK1.5开始Java并发包里提供了两个使用CopyOnWrite机制实现的并发容器,它们是CopyOnWriteArrayList和CopyOnWriteArraySet。CopyOnWrite容器非常有用,可以在非常多的并发场景中使用到。

CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。

阅读全文
0 0