Netty_ByteBuf基本用法(二)

Netty_ByteBuf基本用法二

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

ByteBuf's byte operations

003301_BAwF_1469576.png

#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.

003925_Fg1s_1469576.png

#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. 

004112_r4yJ_1469576.png

#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  there s  no  guarantee  about  the  content  of  writable  bytes  after  calling discardReadBytes(). The writable bytes won t 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  isn t  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  doesn t  clear the  buffer s  content  (for  example,  filling  with  0)  but  clears  the  two pointers.  Please  note  that the semantics of this operation are different from the JDK s ByteBuffer.clear(). Let s look at its functionality.


Figure 5.6 shows a ByteBufwith the three different segments. 

004740_Iu6P_1469576.png

#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.  You ll  see  this  change  once clear() is  called.  Figure 

5.7 shows the ByteBufafter clear()is used. 

004836_DHkd_1469576.png

#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 doesn t 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  you re  decoding  variable  length  data  such  as  NULL-terminated  string,  you ll  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, it s 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 Won t fail as both ByteBuf share the same content and so modifications to one of them are visible on the other too 

Now  let s  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. 

Let s  review  the  relative  operations  first;  I ll  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 didn t change 


Other useful operations 

There are other useful operations  that Ihaven t 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,  it s important to keep the order of the contained objects.  For this purpose,  Netty provides another data container called MessageBuf. 

====END====

转载于:https://my.oschina.net/xinxingegeya/blog/285063

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值