websocket实战(3) 错误处理及配置管理

简介:

通过前面说明,已经轻松构建一个简单的websocket ServerEndPoint了。可以为EndPoint加上解码器,编码器,为EndPoint提供支持。但是,作为一个服务器,遇到错误怎么办?websocket作为一个简单的容器组件,也具备简单配置管理功能。

1.错误处理

1.1@onError

其实很简单,就是在ServerEndPoint类中,添加一个方法,要求该方法被@onError修饰。

如下

1
2
3
4
5
6
7
8
9
@ServerEndpoint ( "/testendpoint" )
public  class  TestEndpoint {
    ...
    @OnError
    public  void  error(Session session, Throwable t) {
       t.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
@ServerEndpoint ( "/echo" )
public  class  EchoEndpoint {
     @OnMessage
     public  String onMessage(String message,Session session) {
         System.out.println( "Received : "  + message);
         int  random =  new  Random().nextInt( 5 );
         if (random== 3 ){
             throw  new  RuntimeException( "自定义异常" );
         } else {
             System.out.println( "random=" +random);
         }
         return  message+ "-" +session.getId();
     }
 
     @OnOpen
     public  void  myOnOpen(Session session) {
         session.getUserProperties().put( "startTime" , new  Date());
         System.out.println( "WebSocket opened: "  + session.getId());
     }
 
     @OnClose
     public  void  myOnClose(CloseReason reason) {
         System.out.println( "Closing a WebSocket due to "  + reason.getReasonPhrase());
     }
 
     @OnError
     public  void  error(Session session, Throwable t) {
         System.out.println( "发生错误,请注意" );
         t.printStackTrace();
     }
}

如果遇到错误,将抛异常如下

发生错误,请注意(error方法中输出)

java.lang.RuntimeException: 自定义异常
    at com.sample.websocket.endpoint.EchoEndpoint.onMessage(EchoEndpoint.java:21)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.apache.tomcat.websocket.pojo.PojoMessageHandlerWholeBase.onMessage(PojoMessageHandlerWholeBase.java:80)
    at org.apache.tomcat.websocket.WsFrameBase.sendMessageText(WsFrameBase.java:393)
    at org.apache.tomcat.websocket.WsFrameBase.processDataText(WsFrameBase.java:494)
    at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:289)
    at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:130)
Closing a WebSocket due to An unrecoverable IOException occurred so the connection was closed(myOnClose调用输出)
    at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:56)
  ....

1.2 Error Handing

主要错误有3种。

Deployment Errors (部署期间,比如tomcat启动)
Errors Originating in Websocket Application Code(websocket endpoint 发生错误) 
Errors Originating in the Container and/or Underlying Connection(连接peer内部错误) 
javax.websocket. CloseReason

CloseReason.CloseCode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public  enum  CloseCodes  implements  CloseReason.CloseCode {
...
/**
  * 1006 is a reserved value and MUST NOT be set as a status code in a
  * Close control frame by an endpoint.  It is designated for use in
  * applications expecting a status code to indicate that the
  * connection was closed abnormally, e.g., without sending or
  * receiving a Close control frame.
  */
CLOSED_ABNORMALLY( 1006 ),
...
}
//1006是一个比较特殊的错误码
//其他错误码,参照Enum CloseCodes

if the local
container determines the session has timed out, the local implementation must use the websocket protocol
close code 
1006 

2.配置管理

2.1 先从javax.websocket.Session说起

Session 代表一个有效连接。周期从(Open ->Close)

wKioL1fmRSPzbyNgAACOZi444dY166.png

简单将Session的方法分为几类(当然你也许有更好的分类)

  1. 配置信息(其中有些配置信息来源于WebContainer)

  2. Session状态信息

  3. 自定义存储信息

  4. 请求信息

  5. Session的操作方法

测试代码

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package  com.sample.websocket.endpoint;
import  javax.websocket.*;
import  javax.websocket.server.ServerEndpoint;
import  java.nio.ByteBuffer;
import  java.util.Iterator;
import  java.util.Set;
 
@ServerEndpoint ( "/config" )
public  class  ReceiveEndpoint {
    @OnMessage
    public  void  textMessage(Session session, String msg) {
       System.out.println( "Text message: "  + msg);
       Set<Session> openSessions = session.getOpenSessions();
       System.out.println( " session.OpenSessions.size"  + openSessions.size());
    }
    @OnMessage
    public  void  binaryMessage(Session session, ByteBuffer msg) {
       System.out.println( "Binary message: "  + msg.toString());
    }
    @OnMessage
    public  void  pongMessage(Session session, PongMessage msg) {
       System.out.println( "Pong message: "  +  msg.getApplicationData().toString());
    }
 
    @OnClose
    public  void  nClose(Session session, CloseReason reason) {
       System.out.println( "Pong message: "  +  reason.getReasonPhrase()+ "-->" +reason.getCloseCode());
    }
 
    @OnError
    public  void  onError(Throwable t){
       t.printStackTrace();
    }
    @OnOpen
    public  void  onOpen(Session session){
       System.out.println( "session.getId()="  + session.getId());
 
       Set<Session> openSessions = session.getOpenSessions();
       System.out.println( " session.OpenSessions.size="  + openSessions.size());
       session.getUserProperties().put( "userName" , "Guest" +session.getId());
 
       Iterator<Session> iterator = openSessions.iterator();
       System.out.println( "open session list===========" );
       while (iterator.hasNext()){
          Session s = iterator.next();
          String sid = s.getId();
          System.out.println( "session.id==>" + sid);
          Object user = s.getUserProperties().get( "userName" );
          System.out.println( "session." +sid+ "username==>" +user);
       }
       System.out.println();
       System.out.println();
 
       WebSocketContainer wsc = session.getContainer();
       System.out.println( "WebSocketContainer Info==========" );
       System.out.println( "webSocketContainer="  + wsc);
       System.out.println( "defaultAsyncTimeout->" +wsc.getDefaultAsyncSendTimeout());
       System.out.println( "defaultMaxBinaryMessageBufferSize-->" +wsc.getDefaultMaxBinaryMessageBufferSize());
       System.out.println( "defaultMaxSessionIdleTimeout-->" +wsc.getDefaultMaxSessionIdleTimeout());
       System.out.println( "installedExtensions.size==>"  + wsc.getInstalledExtensions().size());
       System.out.println();
       System.out.println();
       System.out.println( "session parameter" );
       System.out.println( "session.getMaxBinaryMessageBufferSize()==>" +session.getMaxBinaryMessageBufferSize());
       System.out.println( "session.getMaxIdleTimeout()==>" +session.getMaxIdleTimeout());
       System.out.println( "session.getNegotiatedSubprotocol()==>" +session.getNegotiatedSubprotocol());
       System.out.println( "session.getProtocolVersion()==>" +session.getProtocolVersion());
       System.out.println( "session.getRequestURI()==>"  + session.getRequestURI());
       System.out.println();
       System.out.println();
       Set<MessageHandler> messageHandlers = session.getMessageHandlers();
       Iterator<MessageHandler> messageHandlerIterator = messageHandlers.iterator();
       System.out.println( "MessageHandlers" );
       while (messageHandlerIterator.hasNext()){
          MessageHandler handler = messageHandlerIterator.next();
          System.out.println(handler.toString());
       }
       System.out.println( "session.getUserPrincipal().getName()==>" +session.getUserPrincipal());
    }
}

输出结果如下

session.getId()=0
 session.OpenSessions.size=0
open session list===========

WebSocketContainer Info==========
webSocketContainer=org.apache.tomcat.websocket.server.WsServerContainer@4d3de8ab
defaultAsyncTimeout->-1
defaultMaxBinaryMessageBufferSize-->8192
defaultMaxSessionIdleTimeout-->0
installedExtensions.size==>0


session parameter
session.getMaxBinaryMessageBufferSize()==>8192
session.getMaxIdleTimeout()==>0
session.getNegotiatedSubprotocol()==>
session.getProtocolVersion()==>13
session.getRequestURI()==>/wsexample/config

MessageHandlers
org.apache.tomcat.websocket.pojo.PojoMessageHandlerWholePong@6e710882
org.apache.tomcat.websocket.pojo.PojoMessageHandlerWholeBinary@3ee5c773
org.apache.tomcat.websocket.pojo.PojoMessageHandlerWholeText@1f69b445
session.getUserPrincipal().getName()==>null
Text message: Hello WebSocket!
 session.OpenSessions.size=1


下面是我分析结果

1.session.id是从0递增的

2.session.getOpenSessions(),API定义是获取连接EndPoint的Session的数目,但实际上永远返回1

3.session.getOpenSessions() 在@OnOpen方法中调用返回0,在@OnMessage方法中调用返回1,即便打开了多个连接也是如此。在Tomcat7.72中如此。

4.定义了3个OnMessage修饰的方法,MessageHandler也是三个

5.几个参数从WebSocketContainer中的参数,与Session的参数一致。比如MaxBinaryMessageBufferSize等

6.即使在方法中修改了WebSocketContainer的配置参数值,session中对应的值也不会变。

session.getOpenSessions() API

Return a copy of the Set of all the open web socket sessions that represent connections to the same endpoint to which this session represents a connection. The Set includes the session this method is called on.

调整Session中的若干参数值

1
2
3
4
5
     @OnOpen 
     public  void  onOpen( final  Session session) { 
         session.setMaxIdleTimeout(TIMEOUT); 
         ... 
     }


本文转自 randy_shandong 51CTO博客,原文链接:http://blog.51cto.com/dba10g/1856134,如需转载请自行联系原作者
相关文章
|
前端开发 JavaScript Python
Python Web应用中的WebSocket实战:前后端分离时代的实时数据交换
在前后端分离的Web应用开发模式中,如何实现前后端之间的实时数据交换成为了一个重要议题。传统的轮询或长轮询方式在实时性、资源消耗和服务器压力方面存在明显不足,而WebSocket技术的出现则为这一问题提供了优雅的解决方案。本文将通过实战案例,详细介绍如何在Python Web应用中运用WebSocket技术,实现前后端之间的实时数据交换。
351 0
|
监控 前端开发 API
实战指南:使用Python Flask与WebSocket实现高效的前后端分离实时系统
【7月更文挑战第18天】构建实时Web应用,如聊天室,可借助Python的Flask和WebSocket。安装Flask及Flask-SocketIO库,创建Flask应用,处理WebSocket事件。前端模板通过Socket.IO库连接服务器,发送和接收消息。运行应用,实现实时通信。此示例展现了Flask结合WebSocket实现前后端实时交互的能力。
1491 3
|
JavaScript 网络协议 前端开发
【Nodejs】WebSocket 全面解析+实战演练——(Nodejs实现简易聊天室)
【Nodejs】WebSocket 全面解析+实战演练——(Nodejs实现简易聊天室)
955 0
|
前端开发 JavaScript UED
Python Web应用中的WebSocket实战:前后端分离时代的实时数据交换
【7月更文挑战第16天】在前后端分离的Web开发中,WebSocket解决了实时数据交换的问题。使用Python的Flask和Flask-SocketIO库,后端创建WebSocket服务,监听并广播消息。前端HTML通过JavaScript连接到服务器,发送并显示接收到的消息。WebSocket适用于实时通知、在线游戏等场景,提升应用的实时性和用户体验。通过实战案例,展示了如何实现这一功能。
591 2
|
存储 数据安全/隐私保护
Netty实战(十三)WebSocket协议(一)
WebSocket 协议是完全重新设计的协议,旨在为 Web 上的双向数据传输问题提供一个切实可行的解决方案,使得客户端和服务器之间可以在任意时刻传输消息,因此,这也就要求它们异步地处理消息回执。
847 0
|
消息中间件 缓存 前端开发
Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)
Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)
3265 1
Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)
|
传感器 监控 网络协议
WebSocket 实战:构建高效的实时应用
WebSocket 实战:构建高效的实时应用
WebSocket 实战:构建高效的实时应用
|
前端开发 网络协议 Java
WebSocket理论和实战
WebSocket详解与实战操作
|
数据安全/隐私保护
Netty实战(十四)WebSocket协议(二)
我们之前说过为了将 ChannelHandler 安装到 ChannelPipeline 中,需要扩展了ChannelInitializer,并实现 initChannel()方法
464 0
|
移动开发 前端开发 网络协议
WebSocket从入门到实战
WebSocket从入门到实战
385 0