解决WebSocket 服务器 The WebSocket session [0] has been closed and no method...异常信息
2017-06-20 09:58
429 查看
线程安全的队列来保持所有客户端的Session.
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变量来修饰保证了内存可见性,但实际运行时却发现并没有想象的那么好。当客户端断开链接,时服务器需要发送消息给客户端时.服务端抛出异常:
1
不难看出,是服务端在关闭Session即将Session从线程安全的队列移除时,在发送消息的方法里应该被移除的Session消息却进入了发送消息的环节,在执行getBasicRemote().sendText(clientInfoJson);操作时发生了异常。
解决方法:
Google了大量资料后发现如果要解决这种线程安全的问题,不能通过线程安全的集合来保存Session解决。而应该保存整个类,并通过CopyOnWriteArraySet容器来操作。
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容器也是一种读写分离的思想,读和写不同的容器。
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 session1
1
不难看出,是服务端在关闭Session即将Session从线程安全的队列移除时,在发送消息的方法里应该被移除的Session消息却进入了发送消息的环节,在执行getBasicRemote().sendText(clientInfoJson);操作时发生了异常。
解决方法:
Google了大量资料后发现如果要解决这种线程安全的问题,不能通过线程安全的集合来保存Session解决。而应该保存整个类,并通过CopyOnWriteArraySet容器来操作。
@ServerEndpoint("/getLocation") @Component public 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容器也是一种读写分离的思想,读和写不同的容器。
相关文章推荐
- 完美解决WebSocket 服务器 The WebSocket session [0] has been closed and no method...异常信息
- 出现 com.caucho.hessian.io.HessianServiceException: The service has no method named: XXX 异常的原因及解决方法
- Trying to use an SPWeb object that has been closed or disposed and is no longer valid.
- 关于JPA(Hibernate)+spring在未使用web的情况下使用懒加载,导致no sesssion or session has closed!
- JPA中的failed to lazily initialize a collection of role:xxxx no session or session was closed异常分析与解决
- to disable the entity lazy load, The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
- Error: The Web Server Has Been Locked Down and Is Blocking the DEBUG Verb
- JedisConnectionException: java.net.SocketException: Socket closed;Unknown reply: ; It seems like server has closed the connection.解决办法
- 【异常解决】To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
- 解决SharePoint 文档库itemadded eventhandler导致的上传完成后,编辑页面保持报错的问题,错误信息为“该文档已经被编辑过 the file has been modified by...”
- C#解决微信支付Exception has been thrown by the target of an invocation(调用的目标发生了异常)的问题
- ThreadLocal的实现原理,及使用实例,解决spring,hibernate非web项目下的懒加载 no session or session was closed(2)!
- Silverlight + WCF + EF4 调用出错,Server 端的Exception:The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
- redis异常解决:attempted to load session[xxx] which has been created but not yet serialized.
- SharePoint Designer Check In and Check Out Error – Cannot perform this operation.The file is no longer check out or has been del
- 过滤器解决Hibernate中(no session or session was closed)异常
- ThreadLocal的实现原理,及使用实例,解决spring,hibernate非web项目下的懒加载 no session or session was closed(1)!
- the project file '' has been renamed or is no longer in the solution 解决办法
- asp.net 4.0 has not been registered on the web server解决办法
- Note: This element has no attached source and Javadoc could not be found in the attached Javadoc解决办法