3

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));
    }

java docに基づいているため、 sendBinary がその例外をスローするとは思っていませんでした:

sendBinary void sendBinary(ByteBuffer データ、SendHandler ハンドラ)

例外: IllegalArgumentException - データまたはハンドラーのいずれかが null の場合。

したがって、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 接続が、別のスレッドを送信するための呼び出しが行われたときに、メッセージの送信でビジーである場合 (たとえば、2 つのスレッドが send メソッドを同時に呼び出そうとした場合、または開発者が途中で新しいメッセージを送信しようとした場合)既存のものを送信すると、接続がすでにビジー状態のときに send メソッドが呼び出され、IllegalStateException がスローされる場合があります。

RemoteEndpoint.Async!のような段落はありません。

今の質問

RemoteEndpoint.Async.sendBinary他の何かが同じセッションに書き込んでいる間にセッションを呼び出すことは受け入れられませんか?

受け入れられない場合、リモート エンドポイントに書き込む前にその状態を確認するにはどうすればよいでしょうか。


更新 1:

java.net で同じ問題について議論があったようです。

更新 2:

apache bugzillaの同様のバグ レポートへのリンク。

4

1 に答える 1

1

私も同じ状況になりました。ドキュメントはたわごとです。これが私がそれを処理する方法です。

実際、socketSession をラップするアクターを作成します。send-method が呼び出されると、イベントが生成されます。各アクターは、ワーク スレッドとイベント キューを含む Looper に登録されます。その間、作業スレッドはメッセージを送信し続けます。

そのため、内部で sync-send メソッドを使用します。アクター モデルが同時実行性を確認します。

現在の重要な問題は、ルーパーの数についてです。糸は多すぎても少なすぎてもいけません。ただし、ビジネス ケースごとに数値を見積もり、調整を続けることはできます。

于 2016-09-11T06:08:38.450 に答える