我正在使用 tomcat 8.0.23 来终止我的 websocket 连接。我有以下代码来处理传入的消息:
@OnMessage
public void onMsg(Session session, byte[] request) {
executorService.execute(() ->
session.getAsyncRemote().sendBinary(
ByteBuffer.wrap(getResponse(session, request)), result -> {
if (!result.isOK()) {
LOGGER.catching(result.getException());
}
}
));
}
但我得到以下异常:
Exception in thread "pool-6-thread-10160" java.lang.IllegalStateException: The remote endpoint was in state [BINARY_FULL_WRITING] which is an invalid state for called method
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase$StateMachine.checkState(WsRemoteEndpointImplBase.java:1148)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase$StateMachine.binaryStart(WsRemoteEndpointImplBase.java:1101)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendBytesByCompletion(WsRemoteEndpointImplBase.java:152)
at org.apache.tomcat.websocket.WsRemoteEndpointAsync.sendBinary(WsRemoteEndpointAsync.java:65)
看起来当我尝试同时写入同一个会话时,tomcat 正在抛出该异常。
错误来自此方法:
private void checkState(State... required) {
for (State state : required) {
if (this.state == state) {
return;
}
}
throw new IllegalStateException(
sm.getString("wsRemoteEndpoint.wrongState", this.state));
}
我没想到 sendBinary 会抛出该异常,因为基于java doc:
sendBinary void sendBinary(ByteBuffer 数据,SendHandler 处理程序)
抛出: IllegalArgumentException - 如果数据或处理程序为空。
所以看起来tomcat实现检查状态是否open
在这段代码中:
public synchronized void binaryStart() {
checkState(State.OPEN);
state = State.BINARY_FULL_WRITING;
}
如果不是,open
那么它将抛出该异常。
有趣的是,在java doc for RemoteEndpoint.Basic
(not RemoteEndpoint.Async
) 下,我们读到:
如果在调用发送另一个消息时,此 RemoteEndpoint 底层的 websocket 连接正忙于发送消息,例如,如果两个线程尝试同时调用发送方法,或者如果开发人员在中间尝试发送新消息发送一个现有的,在连接已经很忙时调用的发送方法可能会抛出一个 IllegalStateException。
没有这样的段落RemoteEndpoint.Async
!
现在的问题
RemoteEndpoint.Async.sendBinary
在其他内容写入同一会话时调用会话是否不可接受?
如果不可接受,我如何在尝试写入远程端点之前检查它的状态!
更新1:
看起来在 java.net 上围绕同一问题进行了讨论。
更新 2:
链接到关于 apache bugzilla的类似错误报告。