Netty学习记录
Netty
- 三种I/O模式
Reactor 三种版本
- 第一种版本
- 第二种版本
- 第三种版本
- 如果使用Netty 使用三种 Reactor 模式
Netty 对 Reactor 的支持
主从Reactor 的 源码追踪
- mainReactor 只绑定一次
- Netty给 Netty 分配 ChannelEventGroup的时候使用了哪些算法, 具体是怎么实现的
- 如何实现跨平台
再对 主从模式的group 方法调用的追踪, 它是先将主 Reactor 交给了 他们的super 类 的group变量,
然后 对于从Reactor, 他会再 ServerBootstrapAcceptor 这个东西注册注册监听的acceptor 的 东西。?
然后 childGroup 是怎么选出对应的Channel的呢?
这里是使用register
这里默认选择的实现类 MultithreadEventLoopGroup
调用next 方法
可以看到这里是有两个实现类(策略模式)的 , 第一种是通用, 第二种是 对于大小是2的幂次的。
1 | private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser { |
粘包和半包
TCP 粘包和半包
粘包
粘包现象发生在接收方在一次接收调用中收到多个数据包的数据。例如,发送方连续发送了两个数据包,但接收方在一次接收操作中将这两个数据包的数据一次性接收完毕,导致接收缓冲区中包含两个数据包的内容
出现原因:
- 发送方每次写入的数据 《 套接字缓存区大小
- 接收方读取套接字缓冲区数据不够及时
半包
半包现象发生在接收方在一次接收调用中只接收到一个数据包的一部分数据。这可能是因为数据包在传输过程中被拆分,或者接收方的接收缓冲区大小限制导致
出现原因:
1. 发送方写入数据》套接字缓冲区大小
1. 发送的数据大于协议MTU(最大传输单元), 必须进行拆包
提醒: UDP 不存在粘包和半包的情况, 因为它的消息之间存在界限, 需要一个一个的进行接收。
解决方法
找出消息的边界
- 使用TCP短连接
- 封装成帧
Netty 粘包和半包
下面三个 解码都是继承于ByteToMessageDecoder 这个抽象类
:question: Netty通过数据积累器收集的过程
1 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { |
:question:数据积累器是怎么实现的
- 一种是内存复制的方式 (这是默认的使用方式)
- 一种是组合复制的方式
:question:为什么选择内存复制作为默认的方式,而不是 组合复制
- 组合复制
MERGE_CUMULATOR是通过copy实现,实际操作的是ByteBuf;COMPOSITE_CUMULATOR操作的CompositeByteBuf可以看做是对ByteBuf的封装,其维护了一个ByteBuf的List列表,每次cumulate操作其实把当前的ByteBuf放到List中。我认为这两种cumulate的性能侧重点不同,merge方式提前copy,那么读取时会更快,反之,使用composite的方式在读取时需要遍历List,读取数据时更慢
:question:LengthFieldBasedFrameDecoder 和 它的解码器的 操作
- 四个参数分别代表什么
- lengthFieldOffset
- lengthFieldLength
- lengthAdjustment
- initalBytesToStrips
:question: refCnt 属性的作用是什么?
- 记录 变量的引用次数
常用的二次编解码
对于前端的解码器过程中, 他会把发送的帧数据解码为 字节, 但是我们需要和对象进行关联, 所以需要二级编码器来处理。相应的也就有了从对象到字节的操作, 也就是编码
- 这个类解码器是MessageToMessageDecoder
:question:为什么不把两步操作合二为一 : 因为耦合度高, 不利用代码扩展。 没有分层
ProtoBuffer
使用的方式
先按照语法写好protoBuffer 的 规则
然后 根据你要生成的语言执行下面的指令中的一个, 得到 类文件就可以使用了
worldClock的研读
略
Keepalive 和 idle监测
Keepalive
- 这里和http协议的keepalive 没有关系
idle 监测
Netty 开启 Keepalive 和 idle的方法
Keepalive
- server 端开启keepalive
1 | bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true) |
idle
源码剖析
keepalive 是怎么生效的, 再设置ServerBootstrap的时候, 通过childOption进行设置。
有两种设置 方式
NioChannelOption- NioSocketChannel
ChannelOption- defaultSocketChannel
这个是由一段if-else 判断构成的
idle读的原理
ReaderIdleTimeoutTask的run方法
如果 没有空闲, 重新schedule 然后到时间之后继续操作
如果有空闲, 那么判断是否进来超过1次了 然后进行后续的handler
idle写的原理
同idle读, 但是判断 是否空闲的方式, 不是使用时间间隔, 而是 是否有写入事件的改变
调用了hasOutputChanged
Netty 的锁
略
Netty如何玩转内存使用
能用基本类型, 就别用包装类型
AtomicLong =》 volatile long + static AtomicLongFieldUpdater
zero copy
堆外内存
内存池
Netty源码操作
Netty代码编译 与 总览
buffer 就是 处理字节流那些的
codec 就是用来编解码
stomp 就是用来websocket的