Чтение и запись Int с использованием ByteBuffer в Java NIO

Я хочу передать массив int по сети с помощью канала датаграммы в Java NIO API. Однако функции чтения / записи могут принимать только ByteBuffer в качестве входных данных. Поэтому мне нужно сохранить данные типа int в ByteBuffer, а затем прочитать их в приемнике. Я столкнулся с java.nio.BufferUnderflowException. Вот что я делаю на стороне отправителя:

for(i = 0; i < send_data.length; i++)
{
          //Write the data onto Buffer
          ByteBuffer buffer1 = ByteBuffer.allocate(send_data[i].length*4);
          for(j = 0; j < send_data[i].length; j++)
                     buffer1.putInt(send_data[i][j]);
          buffer1.flip();
          //Transmit the data
          while(buffer1.hasRemaining())
                 channel.write(buffer1);
}

Здесь send_data - это двумерный массив, в котором каждая строка обрабатывается как отдельный пакет данных.

На стороне получателя

for(i = 0; i < k; i++)
{
           ByteBuffer buffer = ByteBuffer.allocate((recvpkt[0].length)*4);
           channel.receive(buffer);
           j = 0;
           while(buffer.hasRemaining())
           {
                  recvpkt[i][j] = buffer.getInt();
                  j = j+1;
           }
 }

Точно так же recvpkt - это 2D-массив, и каждая его строка будет получать по одному пакету из сети.

Я читал, что getInt() читает 4 байта из ByteBuffer и перемещает текущую позицию на 4 байта. Я неправильно использую buffer.flip(). Я новичок в использовании NIO, и у меня возникли трудности с отладкой таких проблем.

ОБНОВИТЬ:

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

ОБНОВЛЕНИЕ 2:

Наконец, после нескольких часов борьбы проблема решена. При получении буфера нужно его перемотать.

  channel.receive(buffer);
  buffer.rewind();

Если вы теперь используете метод getInt в буфере, вы сможете успешно прочитать буфер.


person Aditya    schedule 14.11.2012    source источник
comment
Это настолько неэффективно, насколько это возможно. Вы должны выделить единственный ByteBuffer, хранить в нем все данные, а затем использовать цикл записи для отправки всего этого.   -  person user207421    schedule 14.11.2012
comment
точка занята ... но в настоящее время я хочу понять, почему я получаю вышеупомянутое исключение. Я имею в виду, помимо эффективности, что-то не так с моим кодом?   -  person Aditya    schedule 14.11.2012


Ответы (1)


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

Как только вы это заработаете, вы должны посмотреть, как вы можете повторно использовать свои ByteBuffers и EJP.

person Peter Lawrey    schedule 14.11.2012
comment
flip устанавливает текущее положение буфера как его предел, а текущее положение устанавливается на 0. Не вызовет ли повторное переключение на стороне приемника проблемы? Я имею в виду, что я записываю пакет в буфер за один раз, переворачиваю буфер и затем читаю его. Так почему же во время чтения снова должен произойти переворот? - person Aditya; 14.11.2012
comment
В обоих случаях вы записываете в буфер, и позиция имеет точку, до которой она была записана. Затем вам нужно прочитать от начала до того момента, который был написан. Единственная разница между этими двумя примерами заключается в том, кто пишет, а кто читает, но в обоих случаях вам нужно переключаться между ними. - person Peter Lawrey; 14.11.2012
comment
Несмотря на свое (глупое) название, flip () не является противоположностью самой себе. Вы должны перевернуть перед записью или получением, а затем сжать () или clear (). - person user207421; 15.11.2012
comment
Если вы используете compact () или clear (), вам не нужно flip (), так как он делает это за вас. - person Peter Lawrey; 15.11.2012
comment
Нет, это не так. Это необратимая операция. Правильнее было бы сказать, что flip () подготавливает буфер для записи или получения, а compact () и clear () делают буфер готовым к чтению или установке. Если вы просто используете flip () вместо compact () или clear (), это не сработает. - person user207421; 17.11.2012