当尝试同时写入websocket会话时,Tomcat抛出“远程端点处于状态[BINARY_FULL_WRITING] ...”

时间:2015-10-28 01:33:10

标签: tomcat asynchronous websocket illegalstateexception jsr356

我正在使用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会抛出异常。

错误来自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)

     

抛出:IllegalArgumentException - 如果数据或处理程序为null。

所以看起来tomcat实现会检查this code中状态是否为open

    public synchronized void binaryStart() {
        checkState(State.OPEN);
        state = State.BINARY_FULL_WRITING;
    }

如果它不是open那么它将抛出该异常。

值得注意的是,在RemoteEndpoint.BasicRemoteEndpoint.Async(不是RemoteEndpoint.Async),我们读到:

  

如果此RemoteEndpoint下面的websocket连接正忙   例如,在发出呼叫以发送另一个消息时发送消息   如果两个线程同时尝试调用send方法,或者如果一个   开发人员尝试在中间发送新消息   发送一个现有的,连接时调用的send方法   已经忙碌可能会抛出IllegalStateException。

RemoteEndpoint.Async.sendBinary没有这样的段落!

现在的问题

在其他人写入同一会话时,是否无法在会话中调用> library(rgdal) Loading required package: sp rgdal: version: 1.0-7, (SVN revision 559) Geospatial Data Abstraction Library extensions to R successfully loaded Loaded GDAL runtime: GDAL 1.11.1, released 2014/09/24 Path to GDAL shared files: /usr/local/share/gdal Loaded PROJ.4 runtime: Rel. 4.9.1, 04 March 2015, [PJ_VERSION: 491] Path to PROJ.4 shared files: (autodetected) WARNING: no proj_defs.dat in PROJ.4 shared files Linking to sp version: 1.2-1

如果不可接受,在尝试写入之前如何检查远程端点的状态!

更新1:

看起来java.net上有同样问题的java doc

更新2:

链接到apache bugzilla上的类似discussion

1 个答案:

答案 0 :(得分:1)

我遇到了同样的情况。该文件很糟糕。我就是这样处理的。

实际上,我编写了一个actor来包装socketSession。调用send方法时会产生一个事件。每个actor都将在Looper中注册,其中包含工作线程和事件队列。同时工作线程不断发送消息。

因此,我将在内部使用sync-send方法,actor模型将确保并发性。

现在的关键问题是关于Looper的数量。你知道,你不能做太多或太少的线程。但您仍然可以根据业务案例估算一个数字,并继续进行调整。