【Netty】学习笔记(1)

566 阅读4分钟

小册地址:Netty 入门与实战:仿写微信 IM 即时通讯系统


1. Netty客户端实现双向通信

项目见github:Netty客户端实现双向通信-增加自信,入门demo

2. ByteBuf介绍

demo地址:ByteBuf介绍以及相关api的demo

ByteBuf分为4部分,2指针,2概念

名称 说明
容量:capacity 当前ByteBuf的容量大小
容量上限:maxCapacity 当前ByteBuf的容量上线,capactiy跟maxCapacity都是可以手动设置的
废弃字节 这部分的字节已经被丢弃,属于无效字节
可读字节 在读指针和写指针之间的字节,这部分就是当前ByteBuf中已经存储的数据
可写字节 当前ByteBuf的未被占用(写)的容量,非最大容量,这两个概念需要区分清楚
还可扩容多少字节 这部分看图应该很容易明白,指当前capacity到maxCapacity还剩多少
读指针readIndex 在ByteBuf中使用指针指明当前数据已经读到哪个位置了
写指针writeIndex 使用指针指明当前可以从哪边开始写入数据

一些理解

在ByteBuf中读写都是靠两个指针,读指针所在位置之前的都认为已经被取出,不可以重复读取,读指针到写指针之间的,认为是已经写入但是还没有读出的部分,而写指针表示当前如果有数据写入,会从哪边开始写入

ByteBuf中的api

容量相关api

方法名 作用
capacity() 表示 ByteBuf 底层占用了多少字节的内存(包括丢弃的字节、可读字节、可写字节),不同的底层实现机制有不同的计算方式
maxCapacity() 表示 ByteBuf 底层最大能够占用多少字节的内存,当向 ByteBuf 中写数据的时候,如果发现容量不足,则进行扩容,直到扩容到 maxCapacity,超过这个数,就抛异常
readableBytes() readableBytes() 表示 ByteBuf 当前可读的字节数,它的值等于 writerIndex-readerIndex,如果两者相等,则不可读
isReadable() 当前ByteBuf是否可读,读指针写指针是否在同一个位置
writableBytes() 当前可写的字节数,它的值等于 capacity-writerIndex,如果两者相等,则表示不可写
isWritable() 当前ByteBuf是否可写,但是这个时候,并不代表不能往 ByteBuf 中写数据了, 如果发现往 ByteBuf 中写数据写不进去的话,Netty 会自动扩容 ByteBuf,直到扩容到底层的内存大小为 maxCapacity
maxWritableBytes() 表示可写的最大字节数,它的值等于 maxCapacity-writerIndex

读写指针相关api

ps:这里读写指针的api基本都是一对一对的

方法名 作用
readerIndex() 与 readerIndex(int) 前一个方法返回当前读指针的index,后面的方法设置读指针的index
markReaderIndex() 与 resetReaderIndex() 前面的方法会记录下(源码中对应markIndex属性)当前读指针的index,后面的方法将指针恢复到上面保存的值
writeIndex() 与 writeIndex(int) 前一个方法返回当前写指针的index,后面的方法设置写指针的index
markWriterIndex() 与 resetWriterIndex() 这个与读指针类似,不赘述了

示例代码,代码段1和2是等价的,手册中推介使用第二种

// 代码片段1 
int readerIndex = buffer.readerIndex(); 
// .. 其他操作 
buffer.readerIndex(readerIndex); 
// 代码片段二 
buffer.markReaderIndex(); 
// .. 其他操作 
buffer.resetReaderIndex();

读写api

writeBytes(byte[] src) 和 readBytes(byte[] dst)

将src中的字节数据写入当前ByteBuf中,后面是将ByteBuf中的字节数据写入到dst字节数组中

writeByte(byte b) 和 buffer.readByte()

将字节b写入到ByteBuf中,类似的 API 还有 writeBoolean()、writeChar()、writeShort()、writeInt()、writeLong()、writeFloat()、writeDouble(),后面方法是读取ByteBuf中的一个字节。

与write和read类似的读写api还有 getBytes、getByte() 与 setBytes()、setByte() 系列,唯一的区别就是 get/set 不会改变读写指针,而 read/write 会改变读写指针,这点在解析数据的时候千万要注意。

release() 与 retain()

ByteBuf中的内存都是使用的堆外内存,jvm不能自动回收这些内存,所以需要自己申请内存自己释放内存,不然会导致内存泄漏,最后程序崩溃。 Netty中使用计数的方式标记内存使用次数,刚创建一个ByteBuf时,计数是1,代表当前有一个地方引用过当前的ByteBuf,在使用了ByteBuf的地方调用retain方法,计数加1,调用release()方法,引用计数减1,如果变成0,就直接回收底层内存。

PS: ByteToMessageDecode/MessageToByteEncode:只需要关注转换逻辑的实现,不需要关系ByteBuf内存的申请和回收,这个在后面的笔记中会涉及到。

更多的api,可以参照小册的对应章节,这里不做copy操作了