3

Я использую tomcat 8.0.23 для прекращения подключения к сети. У меня есть следующий код, чтобы заботиться о входящих сообщений:Tomcat throws «Удаленная конечная точка находилась в состоянии [BINARY_FULL_WRITING] ...» при попытке записи в сеанс 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 недействительные (данные ByteBuffer, обработчик SendHandler) sendBinary

Throws: IllegalArgumentException - если данные или обработчик равны нулю.

Так что, похоже, что проверки выполнения Tomcat, чтобы увидеть, если состояние open или нет в this code:

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

и если это не open то выбросит это исключение.

Интересно отметить, что при java doc для RemoteEndpoint.Basic (не RemoteEndpoint.Async) мы читаем:

Если соединение WebSocket, лежащее в основе этой RemoteEndpoint занято посылает сообщение, когда вызов сделан, чтобы отправить еще один, например, , если два потока попытаются вызвать метод отправки одновременно или если разработчик пытается отправить новое сообщение, находясь в середине , отправляя существующий, метод отправки, вызываемый, когда соединение уже занято, может IllegalStateException.

Нет такого абзаца для RemoteEndpoint.Async!

ТЕПЕРЬ ВОПРОС

Разве это не приемлемо вызывать RemoteEndpoint.Async.sendBinary на сессии, а что-то еще пишет в той же сессии?

Если это не приемлемо, как проверить состояние удаленной конечной точки, прежде чем пытаться ее написать!


Update 1:

Похоже, что там было в discussion вокруг того же вопроса на java.net.

Update 2:

Ссылка на аналогичную bug report на апач Bugzilla.

ответ

1

У меня такая же ситуация. Док - это дерьмо. Вот как я справляюсь с этим.

Фактически, я пишу актера, чтобы обернуть socketSession. Он выдает событие, когда вызывается метод send. Каждый актер будет зарегистрирован в Looper, который содержит рабочий поток и очередь событий. Между тем рабочий поток продолжает отправлять сообщения.

Итак, я буду использовать метод sync-send внутри, модель актера будет следить за параллелизмом.

Ключевая проблема теперь в том, что число Looper. Вы знаете, вы не можете сделать ни слишком много, ни слишком мало потоков. Но вы все равно можете оценить количество своих бизнес-кейсов и продолжать его корректировать.

 Смежные вопросы

  • Нет связанных вопросов^_^