Netty的各种简单介绍,总体架构就不介绍了,假设大家感觉的确须要,给我留言我再追加。

这里再推广一个自己做得netty+spring的集成方案,优化netty配置启动,并提供基础server搭建的配置+极少代码的实现方案。

http://download.csdn.net/detail/jackieliyido/9497093

回归正事:咱们直接从从Netty的核心类ByteBuf開始看起。

先看抽象类定义,后面的方法我们详细看核心实现AbstractByteBuf

先看ByteBuf源代码。

@SuppressWarnings("ClassMayBeInterface")
public abstract class ByteBuf implements ReferenceCounted, Comparable<ByteBuf>

先告诉编译器忽略ClassMayBeInterface警告。

然后看到ByteBuf类本身实现了一个netty的引用计数器,以及compareble接口。为什么要写这里,由于看类名的时候第一反应是这个类继承自ByteBuffer.

然后再看凝视,凝视非常重要,作为netty刚開始学习的人是最重要的guide line。

 * <h3>Creation of a buffer</h3>
*
* It is recommended to create a new buffer using the helper methods in
* {@link Unpooled} rather than calling an individual implementation's
* constructor.

推荐使用helper 的方法去创建一块新的buffer,不推荐使用实现类自己的构造器。

下一段:

 * <h3>Random Access Indexing</h3>
*
* Just like an ordinary primitive byte array, {@link ByteBuf} uses
* <a href="http://en.wikipedia.org/wiki/Zero-based_numbering">zero-based indexing</a>.
* It means the index of the first byte is always {@code 0} and the index of the last byte is
* always {@link #capacity() capacity - 1}. For example, to iterate all bytes of a buffer, you
* can do the following, regardless of its internal implementation:
*
* <pre>
* {@link ByteBuf} buffer = ...;
* for (int i = 0; i < buffer.capacity(); i ++) {
* byte b = buffer.getByte(i);
* System.out.println((char) b);
* }
* </pre>

这一段比較水。事实上说的bytebuf是遵循以0为第一位的计数方式。第一眼看到zero-based indexing 没反应过来。后来一看就是说从0開始计数。

嗯。作者非常负责。同一时候学了一个装逼的词 zero-based indexing...

同一时候咱不漏过上面的一句话,buffer.capacity(),这种方法是获取buffer的容量。

buffer.getByte(i),获取指定位置的字节数据

重头戏開始来来了,来看以下一段:

* <h3>Sequential Access Indexing</h3>
*
* {@link ByteBuf} provides two pointer variables to support sequential
* read and write operations - {@link #readerIndex() readerIndex} for a read
* operation and {@link #writerIndex() writerIndex} for a write operation
* respectively. The following diagram shows how a buffer is segmented into
* three areas by the two pointers:
*
* <pre>
* +-------------------+------------------+------------------+
* | discardable bytes | readable bytes | writable bytes |
* | | (CONTENT) | |
* +-------------------+------------------+------------------+
* | | | |
* 0 <= readerIndex <= writerIndex <= capacity
* </pre>

顺序訪问索引。ByteBuf提供两个指针标量来支持读写操作。嗯,这个有点像曾经有面试官问的问题。怎样用循环数组实现队列。

看图上第一段,是被丢弃的字节,这个和我们的电脑磁盘操作一样,删除文件时仅仅是将文件的描写叙述指针从当前位置挪开(好吧。事实上我也不知道叫啥指针甚至于是不是指针),将这块区域置为新空间标识,嗯。大概就是这么个意思

第一段以下有个readerIndex,也就是在0到readIndex之间都是被丢弃的字节(已读完)。readerIndex 到writerIndex之间为可读内容,writeable到容量之间的区域为可写区域。

这里easy误解的地方在于。什么是write,read.这里的读写不是指我们写数据发出去,读数据进来两个动作同一时候发生。而是指单个业务行为比方读数据进来的时候实际发生的底层动作。有点绕。写的好像有点多余。

通过几个图应该就能够看出来了(这部分參考的《netty权威指南》):

初始化ByteBuf的时候:

 *      +---------------------------------------------------------+
* | writable bytes |
* | |
* +---------------------------------------------------------+
* | |
* 0 =readerIndex =writerIndex capacity

写入N个字节后的ByteBuf:

 *      +--------------------------------------+------------------+
* | readable bytes | writable bytes |
<pre name="code" class="java"> * | | |

* +--------------------------------------+------------------+ * | | * 0 =readerIndex N=writerIndex capacity


读取M(M<N)个字节以后:

 *      +-------------------+------------------+------------------+
* | discardable bytes | readable bytes | writable bytes |
* | | | |
* +-------------------+------------------+------------------+
* | | | |
* 0 M=readerIndex N=writerIndex capacity

调用discardReadBytes操作后的ByteBuf:

 *      +-------------------+-------------------------------------+
* | readable bytes | writable bytes |
* | | |
* +-------------------+-------------------------------------+
* | | |
* 0=readerIndex N-M=writerIndex capacity

调用clear方法后:

 *      +---------------------------------------------------------+
* | writable bytes |
* | |
* +---------------------------------------------------------+
* | |
* 0 =readerIndex =writerIndex capacity

认真看完以上几个图后,能够知道readerIndex和writerIndex的工作方式了。

继续回到凝视上,我们掠过代码中关于两个指针的描写叙述后,来到例如以下内容:

 * <h3>Search operations</h3>
*
* For simple single-byte searches, use {@link #indexOf(int, int, byte)} and {@link #bytesBefore(int, int, byte)}.
* {@link #bytesBefore(byte)} is especially useful when you deal with a {@code NUL}-terminated string.
* For complicated searches, use {@link #forEachByte(int, int, ByteBufProcessor)} with a {@link ByteBufProcessor}
* implementation.

这个是关于检索/搜索的描写叙述,对于简单的单子接搜索,推荐使用 ByteBuf.indexOf(int fromIndex,
int toIndex, byte value)、bytesBefore(int index,int length,byte value)以及bytesBefore(byte
value)进行检索,粗粗看了下关于这几个方法的描写叙述。均是指在可读区域(即readerIndex与writerIndex之间部分)内的指定长度范围检索特定值。返回为找到的第一个值的index值,否则返回-1.

关于重置和标记:

 * <h3>Mark and reset</h3>
*
* There are two marker indexes in every buffer. One is for storing
* {@link #readerIndex() readerIndex} and the other is for storing
* {@link #writerIndex() 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 {@link InputStream} except that there's no
* {@code readlimit}.

这里说的rederIndex和writerIndex能够觉得是两个marker,并且能够像使用InputStream一样进行reset,差别在于InputStream有readlimit參数。

补充下InputStream.mark(int readlimit)其中readlimit的作用:在inputStream中。mark的作用是在你mark完一个数据点时,当你继续往下读的时候能够通过调用reset方法回到mark的地点。

可是,这个mark须要有个限制。当你在读readlimit的数据长度内,都会保留mark。超出则不再保留mark

关于衍生缓冲区:

 * <h3>Derived buffers</h3>
*
* You can create a view of an existing buffer by calling either
* {@link #duplicate()}, {@link #slice()} or {@link #slice(int, int)}.
* A derived buffer will have an independent {@link #readerIndex() readerIndex},
* {@link #writerIndex() writerIndex} and marker indexes, while it shares
* other internal data representation, just like a NIO buffer does.
* <p>
* In case a completely fresh copy of an existing buffer is required, please
* call {@link #copy()} method instead.

调用duplicate()、slice()、slice(int index, int length)会创建一个现有缓冲区的视图。衍生的缓冲区有独立的readerIndex、writerIndex和标注索引。共享内部数据。假设须要现有缓冲区的全新副本,能够使用copy()获得。

这里须要说明:duplicate。slice方法均持有独立的读写索引,可是共享内容指针引用。即改动副本的内容将影响原本中的内容。

最后一段。关于转换成JDK已存在的类

 * <h3>Conversion to existing JDK types</h3>
*
* <h4>Byte array</h4>
*
* If a {@link ByteBuf} is backed by a byte array (i.e. {@code byte[]}),
* you can access it directly via the {@link #array()} method. To determine
* if a buffer is backed by a byte array, {@link #hasArray()} should be used.
*
* <h4>NIO Buffers</h4>
*
* If a {@link ByteBuf} can be converted into an NIO {@link ByteBuffer} which shares its
* content (i.e. view buffer), you can get it via the {@link #nioBuffer()} method. To determine
* if a buffer can be converted into an NIO buffer, use {@link #nioBufferCount()}.
*
* <h4>Strings</h4>
*
* Various {@link #toString(Charset)} methods convert a {@link ByteBuf}
* into a {@link String}. Please note that {@link #toString()} is not a
* conversion method.
*
* <h4>I/O Streams</h4>
*
* Please refer to {@link ByteBufInputStream} and
* {@link ByteBufOutputStream}.

数组:假设一个bytebuf是一个数组类型。能够使用array()方法。推断是否为数组的方法为:hasArray()

NIO Buffer:能够通过使用nioBuffer()方法使ByteBuf转换为java.nio.ByteBuffer。

推断能否转换的方法为:nioBufferCount(). nioBufferCount()返回NIO buffer的个数。假设没有则返回-1.

转String:toString(Charset)将可读区域的bytes依照指定编码转换成String,转换不改动readerIndex和writerIndex. toString()打印内存地址,并不转换成String

IO stream:參看日后分析的ByteBufInputStream和ByteBufOutputStream

第一篇先写到这,接下来我们主要分析AbstractByteBuf、HeapByteBuf、DirectByteBuf等几个核心实现。

最新文章

  1. 为模版设计师而生的Twig(上)-Twig使用指南
  2. JQuery插件validate的Remote使用
  3. 玩死人不偿命的CLOUDSTACK
  4. Android 不通过USB数据线调试的方法
  5. SQLite数据转换成sql server数据
  6. Java 多线程编程两个简单的例子
  7. Android过滤Logcat输出
  8. jquery自定义banner图滚动插件---(解决最后一张图片倒回第一张图片的bug)
  9. E. Fish (概率DP)
  10. 服务管理之samba
  11. MyBatis SpringMVC映射配置注意
  12. HTML5特性&amp;&amp;canvas
  13. 根据23423条件,截取字段‘abdecsdsadsadsad’,以ab/dec/sdsa/ds/ads 输出
  14. 使用 vi/vim 时,粘贴进新创建文件或空文件的首行内容丢失的解决方法
  15. PHP 集成开发环境比较
  16. 使用Yii 1.1框架搭建第一个web应用程序
  17. MyEclipse中将普通Java项目convert(转化)为Maven项目
  18. mysql的配置(图解)
  19. Jsp页面跳转和js控制页面跳转的几种方法
  20. Redis客户端 Spring Data Redis(未完)

热门文章

  1. ubuntu搭建LAMP全教程
  2. Python第三方库之openpyxl(9)
  3. Decorator(装饰器模式)
  4. python os模块部分摘录
  5. PTA 08-图9 关键活动 (30分)
  6. tomcat在centos6+上的自启动脚本
  7. Oracle 查看 使用 UNDO 段的事务脚本
  8. BZOJ 3831: [Poi2014]Little Bird【动态规划】
  9. BZOJ 2463: [中山市选2009]谁能赢呢?【博弈】
  10. VBA Split()函数