2016-04-20 3 views
0

Я пытаюсь использовать ByteBuffer для анализа потока пакетов данных, которые я получаю в виде массивов байтов, и может содержать частичные или несколько пакетов. Пакеты имеют переменную длину, поэтому мне нужно проанализировать первые два байта, чтобы получить длину пакета, и кажется, что как только я перевернул() буфер, чтобы прочитать пакет, я не могу вернуться и добавить больше данных, если пакет не завершен.java bytebuffer write read append

Как я могу записать данные в буфер, прочитать некоторые из них, чтобы проверить содержимое, а затем при необходимости добавить к нему дополнительные данные при сохранении прочитанных данных?

class Foo { 

    static final byte[] DATA1 = {0, 13, 2, 65, 88, 80, 55, 51, 52, 84, 82, 43, -111}; 
    static final byte[] DATA2 = {0, 21, 6, 2, 3, 67, 23, 71, -77, 24, -66, -12, -76, 98, 25, 61, 54, -20, 127, -118, 71}; 
    static final byte[] DATA3 = {0, 21, 5, 3, 5, 67}; 
    static final byte[] DATA4 = {23, 72, -50, 24, -66, -9, -31, -86, 25, 61, -95, 75, 71, 47, -102, 0, 13, 2, 84}; 
    static final byte[] DATA5 = {82, 65, 28, 10, 65, 71, 52, 44, 11}; 

    ByteBuffer mByteBuffer = ByteBuffer.allocate(4096); 

    public void test() { 
     mByteBuffer.order(ByteOrder.BIG_ENDIAN); 
     parse(DATA1); 
     parse(DATA2); 
     parse(DATA3); 
     parse(DATA4); 
     parse(DATA5); 
    } 

    public void parse(byte[] bytes) { 
     short byteCount; 
     short crc; 

     mByteBuffer.put(bytes); 
     mByteBuffer.flip(); 

     while (mByteBuffer.remaining() > 5) { 
      byteCount = mByteBuffer.getShort(); 

      // check for invalid buffer 
      if (byteCount < 5) { 
       mByteBuffer.clear(); 
       return; 
      } 

      if (mByteBuffer.remaining() < (byteCount - 2)) { 
       // TODO: incomplete packet, do something 
      } 

      // payload (u8[1 .. 4092]) 
      byte[] payload = new byte[byteCount - 4]; 
      mByteBuffer.get(payload, 0, payload.length); 

      // crc (u16) 
      crc = mByteBuffer.getShort(); 
     } 

     mByteBuffer.clear(); 
    } 
} 

ответ

0

Вызов compact() после getShort(), или вообще после любой последовательности получает или записывает и до следующего read().

+0

не будет 'compact()' удалять любые данные, которые я уже читал, например, количество байтов, которое я просматриваю, чтобы посмотреть, есть ли у меня полный пакет или нет? – jmfox24

-1

Здесь я внес немало изменений, и все они поясняются в комментариях.

private final ByteBuffer mByteBufferAlloc = ByteBuffer.allocate(4096); 
private ByteBuffer mByteBuffer = mByteBufferAlloc.duplicate(); // create a duplicate so we can use without affecting the original allocated buffer so we have a blank slate to reset to 

public void test() 
{ 
    mByteBuffer.order(ByteOrder.BIG_ENDIAN); 
    parse(DATA1); 
    parse(DATA2); 
    parse(DATA3); 
    parse(DATA4); 
    parse(DATA5); 
} 

public void parse(byte[] bytes) 
{ 
    short byteCount; 
    short crc; 

    if(bytes.length > mByteBuffer.remaining()) // Ran out of room, compact anything not yet processed back to the beginning of the buffer and start back with a copy of the allocated buffer 
    { 
     int numBytes = mByteBuffer.position(); 
     if(numBytes > 0) 
     { 
      byte[] toCompact = new byte[numBytes]; 
      ((ByteBuffer) mByteBuffer.flip()).get(toCompact); 
      mByteBuffer = mByteBufferAlloc.duplicate().put(toCompact); 
     } 
     else // nothing in the buffer, simply start fresh 
      mByteBuffer = mByteBufferAlloc.duplicate(); 
    } 
    mByteBuffer.put(bytes); 
    mByteBuffer.flip(); 

    while(mByteBuffer.remaining() > 5) 
    { 
     byteCount = mByteBuffer.getShort(); 

     // check for invalid buffer 
     if(byteCount < 5) 
     { 
      System.err.println("Invalid data, throwing away buffer."); 
      mByteBuffer.clear(); // something was invalid, throw away the entire buffer, but we should probably log an error or something 
      return; 
     } 

     if(mByteBuffer.remaining() < (byteCount - 2)) 
     { 
      // not enough data, wait for more 
      break; 
     } 

     // payload (u8[1 .. 4092]) 
     byte[] payload = new byte[byteCount - 4]; 
     mByteBuffer.get(payload, 0, payload.length); 

     // crc (u16) 
     crc = mByteBuffer.getShort(); 

     int pos = mByteBuffer.position(), limit = mByteBuffer.limit(), capacity = mByteBuffer.capacity(); 
     mByteBuffer = ((ByteBuffer) mByteBuffer.limit(capacity)).slice(); 
     mByteBuffer.limit(limit - pos); // cut the packet off the beginning so we won't parse it again 

     // TODO do something with the packet 
    } 

    mByteBuffer.position(mByteBuffer.limit()).limit(mByteBuffer.capacity()); // reset the position to the end of the added data and the limit to the capacity 
    // mByteBuffer.clear(); Don't want to do this because we want the next call to append to the buffer so retain state 

} 
+0

Вам не нужно все это. 'compact()' достаточно. – EJP

+0

@EJP 'compact' отмечен как устаревший., Но да раздел внутри оператора if, помеченный как« закончился из комнаты », вы можете заменить компактным. Однако уплотнение неэффективно и делает это для каждого пакета, что ухудшит производительность. Именно здесь возникает нехватка кругового буфера в спецификации Java. – LINEMAN78