我正在使用 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)
看起来,当我尝试同时写入同一个 session 时,tomcat 抛出了该异常。
错误来自this method :
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 data, SendHandler handler)
Throws: IllegalArgumentException - if either the data or the handler are null.
所以看起来 tomcat 实现检查状态是否为 open
this code :
public synchronized void binaryStart() {
checkState(State.OPEN);
state = State.BINARY_FULL_WRITING;
}
如果它没有打开
那么它会抛出异常。
有趣的是,在 java doc 下对于 RemoteEndpoint.Basic
(不是 RemoteEndpoint.Async
),我们阅读:
If the websocket connection underlying this RemoteEndpoint is busy sending a message when a call is made to send another one, for example if two threads attempt to call a send method concurrently, or if a developer attempts to send a new message while in the middle of sending an existing one, the send method called while the connection is already busy may throw an IllegalStateException.
RemoteEndpoint.Async
没有这样的段落!
现在是问题
在 session 上调用 RemoteEndpoint.Async.sendBinary
而其他东西正在写入同一 session 是 Not Acceptable 吗?
如果 Not Acceptable ,我该如何在尝试写入之前检查远程端点的状态!
更新 1:
看起来有一个 discussion围绕 java.net 上的相同问题。
更新 2:
类似的链接bug report在 apache bugzilla 上。
最佳答案
我遇到了同样的情况。医生是狗屎。这是我的处理方式。
其实我写了一个actor来包装socketSession。当调用发送方法时,它将产生一个事件。每个 actor 都将注册到一个 Looper 中,该 Looper 包含一个工作线程和一个事件队列。与此同时,工作线程不断发送消息。
因此,我将在内部使用 sync-send 方法,actor 模型将确保并发性。
现在的关键问题是关于Looper的数量。你知道,你不能制造太多或太少的线程。但您仍然可以根据您的业务案例估算一个数字,并不断调整它。
关于尝试同时写入 websocket session 时,Tomcat 抛出 "The remote endpoint was in state [BINARY_FULL_WRITING] ...",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33381420/