Непонятный WritePendingException

243
02 марта 2018, 16:57

Есть сервер, на Java, работающий на асинхронных сокетах. Код сервера, примерно, такой

class ClientHandler implements CompletionHandler<Integer, ByteBuffer> {
  private final AsynchronousSocketChannel socket;
  private static final writer = new WriteHandler();
  public ClientHandler(AsynchronousSocketChannel socket) {
    this.socket = socket;
    doRead();
  }
  private void doRead() {
    ByteBuffer buf = ByteBuffer.allocate(PACKET_SISE);
    socket.read(buf, buf, this);
  }
  private ByteBuffer process(ByteBuffer data) {
    .........
  }
  @Override
  public void completed(Integer result, ByteBuffer attachment) {
    if (attachment.hasRemaining()) {
      socket.close();
      return;
    }
    ByteBuffer buf = process(attachment);
    socket.write(buf, buf, writer);
    doRead();
  }
  @Override
  public void failed(Throwable exc, ByteBuffer attachment) {
    exc.printStackTrace();
  }
}
class WriteHandler implements CompletionHandler<Integer, ByteBuffer> {
  @Override
  public void completed(Integer result, ByteBuffer attachment) {
    if (attachment.hasRemaining())
      socket.close();
  }
  @Override
  public void failed(Throwable exc, ByteBuffer attachment) {
    exc.printStackTrace();
  }
}

Т.е. алгоритм простой - ждем пакета, определенной длины, обрабатываем его и отправляем результат.

И есть Win32 клиент, который работает на блокирующем сокете по такой схеме

while (data = getData()) {
  send(socket, &data, sizeof(data), 0);
  recv(socket, &data, sizeof(data), 0);
}

Сформировали новій пакет, отправили его, дождались результата, формируем новій пакет. Время формирования пакета очень мало.

Так, вот, уже на пятом-шестом пакете вызов на сервере socket.write(buf, buf, writer); приводит к исключению WritePendingException.

Я понимаю, что это за исключение и понимаю как с ним бороться. Я не понимаю как оно может возникнуть? Чтобы оно возникло, я должен записать в сокет данные до того, как отправились предыдущие. Но повторная запись возможна только при получении нового пакета, а это значит, что ответ по предыдущему пакету уже дошел до клиента и был обработан.

Такое ощущение, что в классе AsynchronousSocketChannel не синхронизирован метод write() в результате чего между отправкой данных и снятием флага writePending вклинивается обработка нового пакета

Answer 1

Этот флаг сбрасывается перед вызовом коллбэка completion. Поэтому вариантов решения проблемы два

  1. Инициировать ожидание следующего пакета в коллбэка completion
  2. Реализовывать свою буферизацию
READ ALSO
Где валидировать user input?

Где валидировать user input?

Есть CRUD API к EntityEntity имеет поля id и someString Состоит из трех слоев : Controller, Service, Repository Естественно контроллер знает только о сервисе, а сервис только...

190
Ошибка в конструкторе CustomView

Ошибка в конструкторе CustomView

У меня есть CustomView который рисует текст по ширинеНа андроиде 7

208
Объединение двух запросов Retrofit правильная реализация

Объединение двух запросов Retrofit правильная реализация

Добрый день помогите разобраться с запросамиЕсть два JSON

238
Что лучше при поиске чисел Фибоначчи - рекурсия или простое сложение?

Что лучше при поиске чисел Фибоначчи - рекурсия или простое сложение?

С рекурсией решается быстрее, если искать до 21 числа, а вот все что больше уже намного быстрее решается простым сложениемПочему с рекурсией...

202