我正在使用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会抛出那个异常,因为基于javadoc:
sendBinary void sendBinary(ByteBuffer数据,SendHandler处理程序)
抛出:IllegalArgumentException-如果数据或处理程序为null。
因此,tomcat实现检查该代码中的状态是否为open
:
public synchronized void binaryStart() {
checkState(State.OPEN);
state = State.BINARY_FULL_WRITING;
}
并且如果它不是CCD_ 2,则它将抛出该异常。
值得注意的是,在RemoteEndpoint.Basic
(而不是RemoteEndpoint.Async
)的java文档下,我们读到:
如果此RemoteEndpoint的websocket连接正忙例如,当打电话发送另一条消息时发送消息如果两个线程试图同时调用一个send方法,或者开发人员试图在发送一个现有的,在连接时调用send方法已经很忙可能引发IllegalStateException。
RemoteEndpoint.Async
没有这样的段落!
现在的问题
在会话上调用RemoteEndpoint.Async.sendBinary
,而其他人正在向同一会话写入内容,这是不可接受的吗?
如果这是不可接受的,我该如何在尝试写入之前检查远程端点的状态!
更新1:
看起来在java.net.上也有关于这个问题的讨论
更新2:
链接到关于apachebugzilla的类似错误报告。
我也遇到了同样的情况。医生是个废物。以下是我的处理方法。
事实上,我写了一个演员来包装socketSession。当调用send方法时,它将产生一个事件。每个参与者都将在一个Looper中注册,该Looper包含一个工作线程和一个事件队列。与此同时,工作线程不断发送消息。
所以,我将在里面使用sync-send方法,actor模型将确保并发性。
现在的关键问题是Looper的数量。你知道,你不能做太多或太少的线程。但您仍然可以根据您的业务案例来估计一个数字,并不断调整。