Понадобилось в клиенте реализовать возможность отправки синхронных команд.
Есть базовый класс с объявленным ReetrantLock-ом и созданным на его базе Condition-ом. Первое, что пришло в голову - после захвата блокировки и отправки пакета на сервер делать await(TIMEOUT) у condition, а в методе IoHandler.messageRecive делать для кондишена signalAll(). Предварительно я выставил:
Код | connector.getFilterChain().addLast( "Executor", new ExecutorFilter());
|
Сам код отправки выглядел примерно так:
Код | lock.lock(); try{ handler.setWaitCmdIdAswer(cmd.getCmdId()); executeCmd(cmd); //Исполняется команда и в сессию пишется результат if (handler.getAnswerSyncCmd() == null && isConnected()) answerMonitor.await(30, TimeUnit.SECONDS); //Пришел ответ на синхронную команду либо истек таймаут Container result = handler.getAnswerSyncCmd(); handler.acceptAnswerSyncCmd();*/ } catch (Exception e) { log.error("", e); return null; } finally { lock.unlock(); }
|
Код приема:
Код | public void messageReceived(IoSession session, Object message) throws Exception { ...... Container cont = (Container)message; if (waitCmdIdAswer != null && waitCmdIdAswer.equals(cont.getCmdId())){ answerSyncCmd = cont; conn.getLock().lock(); try{ conn.getAnswerMonitor().signalAll(); }finally{ conn.getLock().unlock(); } }else{ //Пришел ответ на асинхронную команду или просто команда от сервера conn.notifyListenerCmdAnswer(cont); } }
|
В результате получил следующий эффект - сервер получает команду, отрабатывает и возвращает результат. Декодер на клиенте регистрирует получение сообщения, отрабатывает его, возвращает true и... все. Пока не истечет таймаут сообщение в IoHandler не поступает.
Побившись пару часов и не придя к решению, попробовал сделать по феншую:
Код | final WriteFuture writeFuture = session.write(data); writeFuture.awaitUninterruptibly();
if (writeFuture.getException() != null) { session.getConfig().setUseReadOperation(false); return null; }
// retrieve the login response final ReadFuture readFuture =session.read(); readFuture.awaitUninterruptibly();
if (readFuture.getException() != null) { session.getConfig().setUseReadOperation(false); return null; }
// stop blocking inbound messages session.getConfig().setUseReadOperation(false);
// determine if the login info provided was valid final Container reusult = (Container)readFuture.getMessage();
|
Однако проблема осталась точно такая же, после обработки декодером сообщение не поступает ни куда. В данном коде мы просто "повиснем" на readFuture.awaitUninterruptibly();
Подскажите - как быть? |