netty (4) java의 ByteBuffer

이번 포스팅은 netty의 ByteBuf를 알아보기전에 자바의 ByteBuffer에 대해서 알아보겠다.
자바의 ByteBffer는 java 1.4 에 추가 NIO 바이트 버퍼이다.

자바의 Buffer에는 ByteBuffer, CharBuffer, IntBuffe, ShortBuffer, …등등 여러가지가 있다. 이런 버퍼클래스는 내부의 배열 상태를 관리하는 속성이 있다.

capacity

버퍼에 저장할 수 있는 데이터의 최대 크기 한번 저장하면 변경 할 수 없다.

position

읽기 또는 쓰기가 작업 중인 위치를 나타낸다. 객체가 생성될 때 0으로 초기화 되고 입력 혹은 읽을때 자동으로 증가한다.
limit 와 capacity 값보다 작거나 같다.

limit

읽고 쓸 수 있는 공간의 최대치를 나타낸다. limit값은 조절 가능하다. capacity보다 크게 지정 할 수 없다.

자바의 버퍼를 생성하는 방법을 보자.
버퍼를 생성 할 때도 3가지 메서드가 있다.

allocate

JVM의 힙 영역에 바이트 버퍼를 생성한다. 인수는 생성할 바이트 버퍼 크기다. capacity 속성값이다.

allocateDirect

JVM의 힙 영역이 아닌 운영체제의 커널 영역에 버퍼를 생성한다. 앞서 말한 allocate와 동일하다.

wrap

입력된 바이트 배열을 사용하여 버퍼를 생성한다. 입력에 사용된 바이트 배열이 변경되면 wrap를 사용해서 생성한 바이트 버퍼도 변경된다.

코드를 살펴보자

  @Test
  public void createTest() {
    CharBuffer charBuffer = CharBuffer.allocate(11);
    assertEquals(11, charBuffer.capacity());
    assertEquals(false, charBuffer.isDirect());

    ByteBuffer directBuffer = ByteBuffer.allocateDirect(11);
    assertEquals(11, directBuffer.capacity());
    assertEquals(true, directBuffer.isDirect());

    int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0};
    IntBuffer intBuffer = IntBuffer.wrap(array);
    assertEquals(11, intBuffer.capacity());
    assertEquals(false, intBuffer.isDirect());
  }

allocate, allocateDirect, wrap를 생성하는 코드이다.
소스를 보면 더 이해가 빠를것이다.

이제는 생성한 버퍼를 사용해보자.

  @Test
  public void byteBufferTest1() {
    ByteBuffer byteBuffer = ByteBuffer.allocate(11);
    System.out.println(String.format("바이트 버퍼 초기 값 : %s", byteBuffer));
    assertEquals(0, byteBuffer.position());

    byte[] source = "Hello world".getBytes();
    byteBuffer.put(source);
    System.out.println(String.format("11 바이트 기록 후 : %s", byteBuffer));
    assertEquals(11, byteBuffer.position());
  }

최초에 11개의 데이터를 저장 할 수 있는 버퍼를 만들었다.
현재 포지션이 0 인지 알아왔다.
그리고 Hello world라는 byte배열을 생성해서 버퍼에 담았다.
버퍼에 저장한 후에 보면 포지션이 11인걸 알 수 있다. 출력된 내용을 보면 더 자세히 알수 있다.

바이트 버퍼 초기 값 : java.nio.HeapByteBuffer[pos=0 lim=11 cap=11]
11 바이트 기록 후 : java.nio.HeapByteBuffer[pos=11 lim=11 cap=11]

이번에는 버퍼를 읽고 써보자!

  @Test
  public void byteBufferTest3() {
    ByteBuffer byteBuffer = ByteBuffer.allocate(11);
    System.out.println(String.format("바이트 버퍼 초기 값 : %s", byteBuffer));

    byteBuffer.put((byte) 1);
    assertEquals(0, byteBuffer.get());
    assertEquals(2, byteBuffer.position());
    System.out.println(String.format("바이트 버퍼 값 : %s", byteBuffer));
  }

이번에는 1이라는 숫자를 버퍼에 썼다.
그리고나서 다시 get메서드를 사용해서 읽었다. get메서드를 호출 할 때도 position값이 증가한다.
그래서 포지션이 2가 되었다.
출력된 버퍼

바이트 버퍼 초기 값 : java.nio.HeapByteBuffer[pos=0 lim=11 cap=11]
바이트 버퍼 값 : java.nio.HeapByteBuffer[pos=2 lim=11 cap=11]

조금더 이해가 가도록 한개 더 살펴 보겠다.

  @Test
  public void byteBufferTest4() {
    ByteBuffer byteBuffer = ByteBuffer.allocate(11);
    System.out.println(String.format("바이트 버퍼 초기 값 : %s", byteBuffer));

    byteBuffer.put((byte) 10);
    byteBuffer.put((byte) 20);
    assertEquals(2, byteBuffer.position());

    byteBuffer.rewind();
    assertEquals(0, byteBuffer.position());

    assertEquals(10, byteBuffer.get());
    assertEquals(1, byteBuffer.position());

    System.out.println(String.format("바이트 버퍼 값 : %s", byteBuffer));
  }

버퍼에 10과 20를 담았다. 그러면 포지션은 2가 될 것이다.
rewind 함수는 position값이 0이 된다.
그러고 나서 get함수를 호출하면 처음에 들어있는 10이 나오게된다.
get함수를 호출 하였으니 position은 1증가하게 된다.

바이트 버퍼 초기 값 : java.nio.HeapByteBuffer[pos=0 lim=11 cap=11]
바이트 버퍼 값 : java.nio.HeapByteBuffer[pos=1 lim=11 cap=11]

이번엔 flip이란걸 알아보자

  @Test
  public void writeTest() {
    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(11);

    System.out.println(String.format("바이트 버퍼 초기 값 : %s", byteBuffer));

    assertEquals(0, byteBuffer.position());
    assertEquals(11, byteBuffer.limit());

    byteBuffer.put((byte) 10);
    byteBuffer.put((byte) 20);
    byteBuffer.put((byte) 30);
    byteBuffer.put((byte) 40);

    assertEquals(4, byteBuffer.position());
    assertEquals(11, byteBuffer.limit());

    byteBuffer.flip();

    assertEquals(0, byteBuffer.position());
    assertEquals(4, byteBuffer.limit());

    System.out.println(String.format("바이트 버퍼 값 : %s", byteBuffer));
  }

flip은 limit 속성값이 마지막에 기록한 데이터의 위치로 변경된다.
4개의 숫자를 버퍼에 담고 처음에는 limit가 11이 나왔다.
그런후에 flip을 호출하고 limit를 확인하면 4가 나온다.

바이트 버퍼 초기 값 : java.nio.DirectByteBuffer[pos=0 lim=11 cap=11]
바이트 버퍼 값 : java.nio.DirectByteBuffer[pos=0 lim=4 cap=11]

이것으로 자바의 buffer를 알아봤다.
다음에는 netty의 buffer를 알아보겠다.뿅