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等几个核心实现。

netty5源代码探索(一)----ByteBuf初探的更多相关文章

  1. Jedis源代码探索

    [连接池实现] [一致性hash实现]   [Redis客户端-Jedis源代码探索][http://blog.sina.com.cn/s/blog_6bc4401501018bgh.html]   ...

  2. Parrot源代码分析之海贼王

    我们的目的是找到speedup-example在使用Parrot加速的原因,假设仅仅说它源于Context Switch的降低,有点简单了,它究竟为什么降低了?除了Context Switch外是否还 ...

  3. Android源代码学习之六——ActivityManager框架解析

    ActivityManager在操作系统中有关键的数据,本文利用操作系统源代码,逐步理清ActivityManager的框架,并从静态类结构图和动态序列图两个角度分别进行剖析,从而帮助开发者加强对系统 ...

  4. jedis提纲

    A01 - jedis库介绍 A01 - 在多线程下使用Jedis A01 - Jedis的八种调用方式   A02 - API使用文档 A02 - Jedis代码编程使用(简单的使用)   A03 ...

  5. Android SDK上手指南:示例项目

    Android SDK上手指南:示例项目 2013-12-26 15:40 核子可乐译 51CTO 字号:T | T Android SDK示例项目中的应用能够执行种种功能,例如各类用户界面元素.数据 ...

  6. Python源代码剖析笔记3-Python运行原理初探

    Python源代码剖析笔记3-Python执行原理初探 本文简书地址:http://www.jianshu.com/p/03af86845c95 之前写了几篇源代码剖析笔记,然而慢慢觉得没有从一个宏观 ...

  7. 【C++探索之旅】第二部分第一课:面向对象初探,string的惊天内幕

    内容简单介绍 1.第二部分第一课:面向对象初探.string的惊天内幕 2.第二部分第二课预告:掀起了"类"的盖头来(一) 面向对象初探,string的惊天内幕 上一课<[C ...

  8. NoSQL初探之人人都爱Redis:(4)Redis主从复制架构初步探索

    一.主从复制架构简介 通过前面几篇的介绍中,我们都是在单机上使用Redis进行相关的实践操作,从本篇起,我们将初步探索一下Redis的集群,而集群中最经典的架构便是主从复制架构.那么,我们首先来了解一 ...

  9. Android深度探索HAL与驱动开发 第四章 源代码下载和编译

    前面说过Android移植主要就是Linux内核的移植,而Linux内核移植主要是Linux驱动的移植,所以为了开发和测试Linux驱动,有必要学习在Ubuntu Linux下如何搭建两套开发环境:A ...

随机推荐

  1. 一、harbor部署之centos7的基本配置

    1 最小安装centos7 ...安装省略... centos7最小化安装后没ifconfig命令,用 ip addr 命令查看网络信息. 2 配置网络 1.cd /etc/sysconfig/net ...

  2. 设置 mysql事物隔离级别

    SET [GLOBAL | SESSION] TRANSACTION transaction_property [, transaction_property] ... transaction_pro ...

  3. 防火墙iptables介绍

    防火墙: netfilter/iptables是集成在Linux2.4.X版本内核中的包过滤防火墙系统.该架构可以实现数据包过滤,网络地址转换以及数据包管理功能.linux中防火墙分为两部分:netf ...

  4. Luogu【P3609】蹄子剪刀布(DP+滚动数组)

    题目链接 (突然高兴 又一次瞬间想出转移方程并一遍A掉!!233333(虽然从二叉苹果树那题开始我就发现我的方程好像跟别人不大一样 (所以这样就可以名正言顺的水题解了 设f[i][j][k]表示考虑F ...

  5. BZOJ 2140 稳定婚姻 ——二分图

    论二分图的可行边与必须边. 考虑用dinic增广之后的图,一些是必要的割边,一些是可行的割边. 我们首先求出一组可行的最大匹配,那么这些变都是可行的. 然后我们求一遍强连通分量. 如果 scc[u]! ...

  6. 算法复习——数位dp(不要62HUD2089)

    题目 题目描述 杭州人称那些傻乎乎粘嗒嗒的人为 62(音:laoer). 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司 ...

  7. Hibernate批量更新和批量删除批量添加(转)

    通常,在一个Session对象的缓存中只存放数量有限的持久化对象,等到Session对象处理事务完毕,还要关闭Session对象,从而及时释放Session的缓存占用的内存.批量处理数据是指在一个事务 ...

  8. bzoj1853: [Scoi2010]幸运数字 dp+容斥原理

    在中国,很多人都把6和8视为是幸运数字!lxhgww也这样认为,于是他定义自己的“幸运号码”是十进制表示中只包含数字6和8的那些号码,比如68,666,888都是“幸运号码”!但是这种“幸运号码”总是 ...

  9. Codeforces Round #291 (Div. 2) C. Watto and Mechanism [字典树]

    传送门 C. Watto and Mechanism time limit per test 3 seconds memory limit per test 256 megabytes input s ...

  10. koa2 从入门到进阶之路 (一)

    首先我们先来了解一下 Koa 是什么,https://koa.bootcss.com/,这是 Koa 的官方网站,映入眼帘的第一句就是 Koa -- 基于 Node.js 平台的下一代 web 开发框 ...