Chan Chen Coding...

          Netty 4.0 源碼分析(八):Netty 4.0中的io.netty.buffer包

          Netty 4.0的源碼結(jié)構(gòu)與之前的3.X版本發(fā)生了較大的變化,以下是Netty 4.0源碼的層次結(jié)構(gòu)


          netty/

             common/     - utility and logging

             buffer/     - buffer API

             transport/  - channel API and its core implementations

             handler/    - channel handlers

             codec/      - codec framework

             codec-http/ - HTTP, Web Sockets, SPDY, and RTSP codec

             example/    - examples

             all/        - generates an all-in-one JAR

             tarball/    - generates a tarball distribution

           

          在接下來的源碼分析中,筆者打算對每個包實現(xiàn)的功能做詳細(xì)的分析(除了example包,all包和tarball包)。在這篇文章中,筆者將對buffer包進行分析。關(guān)于ByteBufreadIndexwriteIndexcapacity可以閱讀之前的另外一篇文章《Netty 4.0 源碼分析(四):ByteBuf》。

           

          Netty 4.0是一個異步NIO的消息通信框架,在分布式環(huán)境下,服務(wù)器之間的消息傳輸是基于I/O流的,在流傳輸中,字節(jié)是最小的傳輸單位,每個I/O流可以看做是對字節(jié)數(shù)組的操作。Buffer包中的ByteBuf實際上就是一個字節(jié)數(shù)組。

           

          大端(Big Endian)和小段(Little Endian

          在開始討論buffer包之前,有必要了解一下大端(Big Endian)和小段(Little Endian)的區(qū)別。大端(Big Edian)和小端(Little Endian)是內(nèi)存中數(shù)據(jù)儲存的字節(jié)序。不同體系的CPU在內(nèi)存中的數(shù)據(jù)存儲往往存在著差異。例如,Intelx86系列處理器將低序字節(jié)存儲在起始地址,而一些RISC架構(gòu)的處理器,如IBM370主機使用的PowerPCMotorola公司生產(chǎn)的CPU,都將高序字節(jié)存儲在起始位置。這兩種不同的存儲方式被稱為Little EndianBig Endian

          Java中,Big Endian, Little Endian跟多字節(jié)類型的數(shù)據(jù)有關(guān),比如int,short,long型,而對單字節(jié)數(shù)據(jù)byte卻沒有影響。BIG-ENDIAN就是低位字節(jié)排放在內(nèi)存的高端,高位字節(jié)排放在內(nèi)存的低端。而LITTLE-ENDIAN正好相反。

          Big Endian 和 Little Endian

            比如 int a = 0x05060708

            在BIG-ENDIAN的情況下存放為:

            字節(jié)號 0 1 2 3

            數(shù)據(jù)   05 06 07 08

            在LITTLE-ENDIAN的情況下存放為:

            字節(jié)號 0 1 2 3

            數(shù)據(jù)   08 07 06 05


           

          如果網(wǎng)絡(luò)上全部是PowerPC,SPARCMotorola CPU的主機那么不會出現(xiàn)任何問題,但由于實際存在大量的IA架構(gòu)的CPU,所以經(jīng)常出現(xiàn)數(shù)據(jù)傳輸錯誤。

          所有網(wǎng)絡(luò)協(xié)議都是采用Big Endian的方式來傳輸數(shù)據(jù)的。所以有時我們也會把Big Endian方式稱之為網(wǎng)絡(luò)字節(jié)序。當(dāng)兩臺采用不同字節(jié)序的主機通信時,在發(fā)送數(shù)據(jù)之前都必須經(jīng)過字節(jié)序的轉(zhuǎn)換成為網(wǎng)絡(luò)字節(jié)序后再進行傳輸。

           

          Netty 4.0的,默認(rèn)的字節(jié)序是Big Endian(網(wǎng)絡(luò)字節(jié)序),在io.netty.buffer.Unpooled類中,定義了兩個ByteOrder類型的靜態(tài)變量

              /**
               * Big endian byte order.
               
          */
              public static final ByteOrder BIG_ENDIAN = ByteOrder.BIG_ENDIAN;
              /**
               * Little endian byte order.
               
          */
              public static final ByteOrder LITTLE_ENDIAN = ByteOrder.LITTLE_ENDIAN;

           

           如果要改變改變字節(jié)序,可以調(diào)用io.netty.buffer.ByteBuf接口的order(ByteOrder endianness)方法。調(diào)用order方法,可以返回當(dāng)前ByteBuf對象的字節(jié)序。

              /**
               * Returns the endianness of this buffer.
               
          */
              ByteOrder order();
              /**
               * Returns a buffer with the specified endianness which shares the whole region,
               * indexes, and marks of this buffer.  Modifying the content, the indexes, or the marks of the
               * returned buffer or this buffer affects each other's content, indexes, and marks.  If the
               * specified endianness is identical to this buffer's byte order, this method can
               * return {
          @code this}.  This method does not modify readerIndex or writerIndex of this buffer.
               
          */
              ByteBuf order(ByteOrder endianness);

           

          ChannelByteBuf的理解

          Netty中,Channel是負(fù)責(zé)數(shù)據(jù)讀寫的對象,類似于java舊的I/OstreamChannel是雙向的,既可以write,也可以read。在NIO中,用戶不能直接從Channel中讀寫數(shù)據(jù),而是應(yīng)該通過ByteBuf來進行讀寫操作,然后通過ByteBuf讀寫數(shù)據(jù)到Channel中。可以想象一個伐木場,Channel就是某個含有大量需要砍伐的樹木(數(shù)據(jù))的采伐區(qū),要想取得這些樹木(數(shù)據(jù)),就需要一輛卡車來運輸這些樹木(數(shù)據(jù)),這里的卡車就是ByteBuf(緩沖器),當(dāng)卡車(ByteBuf)滿載而歸的時候,我們再從卡車中獲得樹木(數(shù)據(jù))。

           

          Netty 4.0中的buffer

          Netty 4.0中的io.netty.buffer包,總共定義了七個接口,十五個類,一個Enums類型。下圖是他們之間的關(guān)系


          Io.netty.buffer包中的關(guān)系

          Unpooled是個幫助類,是一個final class,并且它的構(gòu)造器也是私有的,這意味的無法被別的類繼承,也無法通過new運算符來創(chuàng)建一個Unpooled對象。Unpool類的目的就是用于創(chuàng)建ByteBuf對象。

              /**
               * Creates a new big-endian Java heap buffer with the specified
               * {
          @code capacity}.  The new buffer's {@code readerIndex} and
               * {
          @code writerIndex} are {@code 0}.
               
          */
              public static ByteBuf buffer(int initialCapacity, int maxCapacity) {
                  if (initialCapacity == 0 && maxCapacity == 0) {
                      return EMPTY_BUFFER;
                  }
                  return new HeapByteBuf(initialCapacity, maxCapacity);
              }
              /**
               * Creates a new big-endian direct buffer with the specified
               * {
          @code capacity}.  The new buffer's {@code readerIndex} and
               * {
          @code writerIndex} are {@code 0}.
               
          */
              public static ByteBuf directBuffer(int initialCapacity, int maxCapacity) {
                  if (initialCapacity == 0 && maxCapacity == 0) {
                      return EMPTY_BUFFER;
                  }
                  return new DirectByteBuf(initialCapacity, maxCapacity);
              }
              /**
               * Creates a new big-endian buffer which wraps the sub-region of the
               * specified {
          @code array}.  A modification on the specified array's
               * content will be visible to the returned buffer.
               
          */
              public static ByteBuf wrappedBuffer(byte[] array, int offset, int length) {
                  if (length == 0) {
                      return EMPTY_BUFFER;
                  }
                  if (offset == 0 && length == array.length) {
                      return wrappedBuffer(array);
                  }
                  return new SlicedByteBuf(wrappedBuffer(array), offset, length);
              }  
              /**
               * Returns a new big-endian composite buffer with no components.
               
          */
              public static CompositeByteBuf compositeBuffer(int maxNumComponents) {
                  return new DefaultCompositeByteBuf(maxNumComponents);
              } 
              /**
               * Creates a read-only buffer which disallows any modification operations
               * on the specified {
          @code buffer}.  The new buffer has the same
               * {
          @code readerIndex} and {@code writerIndex} with the specified
               * {
          @code buffer}.
               
          */
              public static ByteBuf unmodifiableBuffer(ByteBuf buffer) {
                  if (buffer instanceof ReadOnlyByteBuf) {
                      buffer = ((ReadOnlyByteBuf) buffer).unwrap();
                  }
                  return new ReadOnlyByteBuf(buffer);
              }


          通過Unpooled創(chuàng)建ByteBuf對象:

          ByteBuf heapBuffer    = Unpooled.buffer(128);

          ByteBuf directBuffer  = Unpooled.directBuffer(256);

          ByteBuf wrappedBuffer = Unpooled.wrappedBuffer(new byte[128], new byte[256]);

           

          ByteBuf的類型

          Netty 4.0中,ByteBuf有以下幾種類型,分別是HeapByteBufWrappedByteBufDirectByteBufCompositeByteBuf HeapByteBufUnpooled類中是默認(rèn)的ByteBuf類型,通過Unpooled.buffer()取得。某人的緩沖器大小是256字節(jié)。

          WrappedByteBuf用于包裝一個字節(jié)數(shù)組或者一個ByteBuf,通過Unpooled.wrappedBuffer(byte[] array)或者Unpooled.wrappedBuffer(ByteBuf bytebuf)取得。

          DirectByteBufNIO的基本緩存器。

          CompositeByteBuf是一個組合緩沖器,將多個ByteBuf對象組合在同一個緩沖器中。

          具體看如下代碼:

          public class ByteBufTypeDemo {
                public static void main(String[] args){
                     byte[] byteArrayA = {1, 2};
                     byte[] byteArrayB = {3, 4};
                    
                     ByteBuf heapBuffer = Unpooled.buffer();
                     System.out.println("/***********Heap ByteBuf***************/");
                     System.out.println("Default Byte Order: " + heapBuffer.order());
                     System.out.println("Default Heap Buffer Capacity: " + heapBuffer.capacity());
                     System.out.println();
                     System.out.println();
                    
                     ByteBuf wrappedBufferA = Unpooled.wrappedBuffer(byteArrayA);
                     System.out.println("/***********Wrapped ByteBuf***************/");
                     for(int i = 0; i < wrappedBufferA.writerIndex(); i++){
                           System.out.println(wrappedBufferA.getByte(i));
                     }
                     System.out.println();
                     System.out.println();
                    
                     ByteBuf wrappedBufferB = Unpooled.wrappedBuffer(byteArrayB);
                     ByteBuf compositeByteBuf = Unpooled.compositeBuffer().addComponent(wrappedBufferA).addComponent(wrappedBufferB);
                     Iterator<ByteBuf> compositeIterator = ((CompositeByteBuf)compositeByteBuf).iterator();
                     System.out.println("/***********Composite ByteBuf***************/");
                     while(compositeIterator.hasNext()){
                           ByteBuf tempBuf = compositeIterator.next();
                           for(int i = 0; i < 2;i++){
                                System.out.println(tempBuf.getByte(i));
                           }
                     }
                     System.out.println();
                     System.out.println();
           
                     System.out.println("/***********Direct ByteBuf***************/");
                     ByteBuf directByteBuf = (DirectByteBuf)Unpooled.directBuffer();
                     System.out.println("Has NIO Buffer? " + directByteBuf.hasNioBuffer());
                     System.out.println();
                     System.out.println();
                     System.out.println("/*****************End*********************/");
                }
          }

           

           

          參考引用:http://baike.baidu.com/view/2368412.htm

           

          備注:因為筆者開始寫Netty源碼分析的時候,Netty 4.0還是處于Alpha階段,之后的API可能還會有改動,筆者將會及時更改。使用開源已經(jīng)有好幾年的時間了,一直沒有時間和精力來具體研究某個開源項目的具體實現(xiàn),這次是第一次寫開源項目的源碼分析,如果文中有錯誤的地方,歡迎讀者可以留言指出。對于轉(zhuǎn)載的讀者,請注明文章的出處。

          希望和廣大的開發(fā)者/開源愛好者進行交流,歡迎大家的留言和討論。



          -----------------------------------------------------
          Silence, the way to avoid many problems;
          Smile, the way to solve many problems;

          posted on 2012-11-27 11:34 Chan Chen 閱讀(13505) 評論(2)  編輯  收藏 所屬分類: Netty

          評論

          # re: Netty 4.0 源碼分析(八):Netty 4.0中的io.netty.buffer包[未登錄] 2013-01-12 14:03

          把這一套看完了,Netty的常用API作用及用法我基本上都清楚,灰常謝謝啊!  回復(fù)  更多評論   

          # re: Netty 4.0 源碼分析(八):Netty 4.0中的io.netty.buffer包 2015-12-10 18:16 tracie

          請問一下你的圖是用什么工具畫的?  回復(fù)  更多評論   

          主站蜘蛛池模板: 灵寿县| 阿合奇县| 宽甸| 鸡西市| 积石山| 五指山市| 迁安市| 闵行区| 六安市| 宜昌市| 申扎县| 上思县| 宣恩县| 洪江市| 黄冈市| 铜山县| 阿克苏市| 元谋县| 北碚区| 临泉县| 大港区| 蒲江县| 喀喇沁旗| 大关县| 宁武县| 封开县| 应用必备| 信阳市| 江川县| 吐鲁番市| 闵行区| 进贤县| 伊川县| 清水县| 靖边县| 博乐市| 绥江县| 玉林市| 沂源县| 东乌珠穆沁旗| 恩平市|