通过前面说明,已经轻松构建一个简单的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)
简单将Session的方法分为几类(当然你也许有更好的分类)
配置信息(其中有些配置信息来源于WebContainer)
Session状态信息
自定义存储信息
请求信息
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);
...
}
|
