Netty_ByteBuf基本用法(二)

Netty_ByteBuf基本用法二

上一篇http://my.oschina.net/xinxingegeya/blog/283227

ByteBuf's byte operations

Netty_ByteBuf基本用法(二)_第1张图片

#1 Segment(段) that holds bytes that can be discarded(废弃的) as they were read before 

#2 Segment that holds the actual readable content that was not read yet 

#3 Segment that contains the left space of the buffer and so to which more bytes can be written 


Discardable bytes 

The discardable bytes segment contains  the bytes that were already read by a read operation and so may be discarded. Initially, the size of this segment is 0, but its size increases up to the writerIndex as  read  operations  are  executed.  This  only  includes  read  operations;  get operations  do  not  move  the readerIndex.  The read  bytes  can  be  discarded  by  calling discardReadBytes()to reclaim unused space. 

Figure 5.4 shows what the segments of a ByteBuflook like before discardReadBytes() is called.

Netty_ByteBuf基本用法(二)_第2张图片

#1 Segment that holds bytes that can be discarded as they was read before 

#2 Segment that holds the actual readable content that was not read yet 

#3 Segment that contains the left space of the buffer and so to which more bytes can be written 

As  you  can  see,  the  discardable  bytes  segment  contains  some  space  that  is  ready  for  reuse. This can be achieved by calling discardReadBytes(). 


Figure 5.5 shows how the call of discardReadBytes() will affect the segments. 

Netty_ByteBuf基本用法(二)_第3张图片

#1 Segment that holds the actual readable content that was not read yet. This starts now on index 0 

#3 Segment that contains the left space of the buffer and so to which more bytes can be written. This is now bigger as it growed by the space that was hold by the discardable bytes before 

Note  that  theres  no  guarantee  about  the  content  of  writable  bytes  after  calling discardReadBytes(). The writable bytes wont be  moved in  most cases and could even be filled with completely different data depending on the underlying buffer implementation. Also,  you  may  be  tempted(动心)  to  frequently  call discardReadBytes() to  provide  the ByteBuf with  more  writable  space  again.  Be  aware  that  discardReadBytes() will  most likely involve(涉及) a memory copy as it needs to move the readable bytes (content) to the start of the ByteBuf.  Such  an  operation  isnt  free  and  may  affect(影响)  performance,  so  only  use  it  if  you need it and will benefit from  it. Thus would be for  example if you need to free  up  memory as soon as possible. 


Readable bytes (the actual content)

This segment is where the actual data is stored. Any operation whose name starts with read or skip  will  get  or  skip  the  data  at  the  current readerIndex and  increase  it  by  the  number  of read bytes. If the argument of the read operation is also a ByteBufand no destination index is specified, the specified destination buffer's writerIndexis increased together. If  there's  not  enough  content  left, IndexOutOfBoundExceptionis  raised.  The  default value of newly allocated, wrapped, or copied buffer's readerIndexis 0. The following listing shows how to read all readable data. 

Listing 5.8 Read data 

// Iterates the readable bytes of a buffer. 
ByteBuf buffer = ...; 
while (buffer.readable()) { 
    System.out.println(buffer.readByte()); 
}


Writable bytes 

This segment is an undefined space which needs to be filled. Any operation whose name starts with  write  will  write  the  data  at  the  current writerIndex and increase  it  by  the  number  of written bytes. If the argument of the write operation is also a ByteBufand no source index is specified, the specified buffer's readerIndexis increased together. If  there's  not  enough  writable  bytes  left, IndexOutOfBoundException is  raised.  The default value of newly allocated buffer's writerIndexis 0. The following listing shows an example that fills the buffer with random intvalues until it runs out of space. 

Listing 5.9 Write data 

// Fills the writable bytes of a buffer with random integers. 
ByteBuf buffer = ...; 
while (buffer.writableBytes() >= 4) { 
    buffer.writeInt(random.nextInt());
}


Clearing the buffer indexes 

You  can  set  both readerIndex and writerIndex to  0  by  calling clear().  It  doesnt  clear the  buffers  content  (for  example,  filling  with  0)  but  clears  the  two pointers.  Please  note  that the semantics of this operation are different from the JDKs ByteBuffer.clear(). Lets look at its functionality.


Figure 5.6 shows a ByteBufwith the three different segments. 

Netty_ByteBuf基本用法(二)_第4张图片

#1 Segment that holds bytes that can be discarded as they were read before 

#2 Segment that holds the actual readable content that was not read yet 

#3 Segment that contains the left space of the buffer and so to which more bytes can be written 

As  before,  it  contains  three  segments.  Youll  see  this  change  once clear() is  called.  Figure 

5.7 shows the ByteBufafter clear()is used. 

Netty_ByteBuf基本用法(二)_第5张图片

#1 Segment is now as big as the capacity of the ByteBuf, so everything is writable 

Compared  to discardReadBytes(),  the clear() operation  is  cheap,  because  it  adjusts pointers and doesnt need to copy any memory. 


Search operations 

Various indexOf() methods  help  you  locate  an  index  of  a  value  which  meets  a  certain criteria.  Complicated  dynamic  sequential  search  can  be  done  with ByteBufProcessorimplementations as well as simple static single-byte search. If  youre  decoding  variable  length  data  such  as  NULL-terminated  string,  youll  find the bytesBefore(byte)method useful. Let's imagine you've written an application, which has to integrate with flash sockets, which uses NULL-terminated content. Using the bytesBefore()method, you can easily consume data from Flash without manually readying every byte in the data to check  for NULL bytes. Without the ByteBufProcessoryou would need to do all this work by yourself. Also it is more efficient as it needs less bound checks during processing. 


Mark and reset 

As  stated  before,  there  are  two  marker  indexes  in  every  buffer.  One  is  for  storing readerIndexand the other is for storing writerIndex. You can always reposition one of the two  indexes  by  calling  a  reset  method.  It  works  in  a  similar  fashion  to  the  mark  and  reset methods in an InputStreamexcept that there are no read limits. Also,  you  can  move  them  to  an  exact  index  by  calling readerIndex(int) or writerIndex(int).Be aware that trying to  set  the readerIndex or writerIndex to  an invalid position will cause an IndexOutOfBoundException. 


Derived(衍生导出) buffers 

To  create  a  view  of  an  existing  buffer,  call duplicate(), slice(), slice(int,  int), readOnly(),  or order(ByteOrder).  A  derived  buffer  has  an  independent readerIndex, writerIndex, and marker indexes, but it shares other internal data representation the way a NIO ByteBufferdoes. Because it shares the internal data representation, its cheap to create and is the preferred way if, for example, you need a slice of a ByteBufin an operation. If  a  fresh  copy  of  an  existing  buffer  is required,  use  the copy() or copy(int,  int) method instead. The following listing shows how to work with a slice of a ByteBuf. 

Listing 5.10 Slice a ByteBuf 

Charset utf8 = Charset.forName(ìUTF-8ì); 
ByteBuf buf = Unpooled.copiedBuffer(ìNetty in Action rocks!ì, utf8); #1 
ByteBuf sliced = buf.slice(0, 14); #2 
System.out.println(sliced.toString(utf8); #3 
buf.setByte(0, (byte) íJí); #4 
assert buf.get(0) == sliced.get(0); #5

#1 Create ByteBuf which holds bytes for given string 

#2 Create new slice of ByteBuf which starts at index 0 and ends at index 14 

#3 Contains Netty in Action 

#4 Update byte on index 0 

#5 Wont fail as both ByteBuf share the same content and so modifications to one of them are visible on the other too 

Now  lets  look  at  how  to  create  a  copy  of  a ByteBuf and  how  that  differs  from  a  slice.  The following listing shows how to work with a copy of a ByteBuf. 


Read/write operations

There are two main types of read/write operations: 

  1. Index based get/set operations that set or get bytes on a given index. 

  2. Read/write  operations  that  either  read  bytes  from  the  current  index  and  increase  them or write to the current index and increase it. 

Lets  review  the  relative  operations  first;  Ill  mention  only  the  most  popular  for  now.  For  a complete overview, refer to the API docs. 

Charset utf8 = Charset.forName(ìUTF-8ì); 
ByteBuf buf = Unpooled.copiedBuffer(ìNetty in Action rocks!ì, utf8); #1 
System.out.println((char) buf.getByte(0)); #2 
// #3 
int readerIndex = buf.readerIndex(); 
int writerIndex = buf.writerIndex(); 
buf.setByte(0, (byte) íBí); #4 
System.out.println((char) buf.getByte(0)); #5 
// #6 
assert readerIndex = buf.readerIndex(); 
assert writerIndex = buf.writerIndex();

#1 Create a new ByteBuf which holds the bytes for the given String 

#2 Prints out the first char which is N 

#3 Store the current readerIndex and writerIndex 

#4 Update the byte on index 0 with the char B 

#5 Prints out the first char which is B now as I updated it before 

#6 Check that the readerIndex and writerIndex did not change which is true as relative operations never modify the indexes. 


Charset utf8 = Charset.forName(ìUTF-8ì); 
ByteBuf buf = Unpooled.copiedBuffer(ìNetty in Action rocks!ì, utf8); #1 
System.out.println((char) buf.readByte()); #2 
// 
int readerIndex = buf.readerIndex(); #3 
int writerIndex = buf.writerIndex(); #4 
buf.writeByte( (byte) í?í); #5 
// #6 
assert readerIndex = buf.readerIndex(); 
assert writerIndex != buf.writerIndex();

#1 Create ByteBuf which holds bytes for given string 

#2 Prints first char N 

#3 Store current readerIndex and writerIndex 

#4 Update byte on index 0 with char B 

#5 Prints first char B that I updated 

#6 Check readerIndex and writerIndex didnt change 


Other useful operations 

There are other useful operations  that Ihavent mentioned yet, but they often come  in  handy, depending on your use case. Table 5.5 gives an overview of them and explains what they do. 

isReadable() 

Returns true if at least one byte can be read. 

isWritable() 

Returns true if at least one byte can be written. 

readableBytes() 

Returns the number of bytes that can be read. 

writablesBytes() 

Returns the number of bytes that can be written.

capacity() 

Returns the number of bytes that the ByteBufcan hold. After this it will try to expand again until maxCapacity() is reached. 

maxCapacity() 

Returns the maximal number of bytes the ByteBufcan hold. 

hasArray() 

Returns true if the ByteBufis backed by a byte array. 

array() 

Returns the byte array if the ByteBufis backed by a byte array, otherwise throws an UnsupportedOperationException.

You may need to work with normal objects called POJOs. These need to be stored and retrieved later. Often,  its important to keep the order of the contained objects.  For this purpose,  Netty provides another data container called MessageBuf. 

====END====

你可能感兴趣的:(Netty_ByteBuf基本用法(二))