2015-05-20 11 views
0

Я использую java AsynchronousSocketChannel от nio2 в моем проекте. Я использую oracle jdk 1.7.0_80 на ubuntu 14.04 тоже.Операция чтения Java AsynchronousSocketChannel

Мой проект - это сервер, который обрабатывает двоичные данные. код вызывает операцию чтения рекурсивно в завершенном способе CompletionHandler анонимного класса, например:

private final CompletionHandler<Integer,AsynchronousSocketChannel> readHandler=new CompletionHandler<Integer,AsynchronousSocketChannel>(){ 

    @Override 
    public void completed(Integer result,AsynchronousSocketChannel attachment) { 
     if(result<0){ 
      attachment.close(); 
      return; 
     } 
     attachment.read(swap, attachment, this); 
    } 
} 

Если переменная своп экземпляр ByteBuffer.

Видимо, все работает хорошо. Но есть пакет с общим размером 3832 байт, когда сервер получает весь пакет без сегментов, проблем нет. Однако иногда этот пакет разделяется на две или более части (сегменты TCP). например: размер первого сегмента составляет 2896 байт, а размер второго - 936 байт.

Последний сегмент не имеет заголовка, это разрушает мой алгоритм. Я бы хотел знать, есть ли способ, чтобы API вызывал «завершенный» метод только после прочтения всего пакета?

Я увеличил SO_RCVBUF до 64K, но он не работает.

ответ

0

Я хотел бы знать, есть ли способ, чтобы API вызывал «завершенный» метод только после прочтения всего пакета?

Нет, не существует способа сделать это.

Протокол TCP может разбивать поток байтов в пакетах произвольного размера. Протокол уровня приложения, который вы используете поверх TCP, не должен полагаться на сообщения, которые всегда отправляются полностью в одном пакете TCP.

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

Один из распространенных способов сделать это - префикс сообщений уровня приложения по полю длины. Например, сообщение уровня приложения состоит из поля из 4 байтов, которые содержат длину остальной части сообщения. Когда вы получаете сообщение, вы сначала получаете длину, а затем вы должны продолжать получать, пока не получите столько байтов, которые затем можете собрать в сообщение на уровне приложения.

API AsynchronousSocketChannel API не может автоматически собирать сообщения на уровне приложений, поскольку он ничего не знает о вашем протоколе уровня приложения.

+0

Спасибо Йеспер. Я последовал твоему намеку. – snop

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