Netty学习之旅------源码分析Netty解码编码器实现原理

本文详细解读了Netty框架中ByteToMessageDecoder类的内存管理和事件处理机制,包括ByteBuf的累积缓存区操作、容量扩展、解码事件如handlerRemoved、channelRead和channelInactive的处理,以及编码器MessageToByteEncoder的基础概念。
摘要由CSDN通过智能技术生成

@Override

public ByteBuf cumulate(ByteBufAllocator alloc, ByteBuf cumulation, ByteBuf in) { //@1

ByteBuf buffer;

if (cumulation.writerIndex() > cumulation.maxCapacity() - in.readableBytes() //@2

|| cumulation.refCnt() > 1) { //@3

// Expand cumulation (by replace it) when either there is not more room in the buffer

// or if the refCnt is greater then 1 which may happen when the user use slice().retain() or

// duplicate().retain().

//

// See:

// - https://github.com/netty/netty/issues/2327

// - https://github.com/netty/netty/issues/1764

buffer = expandCumulation(alloc, cumulation, in.readableBytes()); //@4

} else {

buffer = cumulation;

}

buffer.writeBytes(in); // @5

in.release(); //@6

return buffer;

}

};

代码@1:参数1:具体的内存分配器,参数2:已累计接收的自己缓冲,参数3:本次读取的字节缓冲区。

代码@2:首先检测当前的累积缓存区是否能够容纳新增加的ByteBuf,如果容量不够,则需要扩展ByteBuf,为了避免内存泄漏,手动去扩展。

代码@3:如果累积缓存区引用数超过1,也需要扩展。

代码@4:扩充累积缓存区。

代码@5:将新输入的字节写入到累积缓存区。

代码@6:释放缓存区。

代码@4:扩展缓冲区实现。

static ByteBuf expandCumulation(ByteBufAllocator alloc, ByteBuf cumulation, int readable) {

ByteBuf oldCumulation = cumulation;

cumulation = alloc.buffer(oldCumulation.readableBytes() + readable);

cumulation.writeBytes(oldCumulation);

oldCumulation.release();

return cumulation;

}

这里有个非常关键的点:每次扩展的时候,都是产生一个新的累积缓存区,这里主要是确保每一次通道读,所涉及的缓存区不是同一个,这样减少释放跟踪的难度,避免内存泄露。

2.2 相关事件处理


解码器 ByteToMessageDecoder 在 Netty 中属于 InBound(输入方向)。主要关注的事件包括 handlerRemoved、channelReader、channelReadComplete、channelInactive。

2.2.1 handlerRemoved事件

handler从ChannelPipeline中移除时调用。

@Override

public final void handlerRemoved(ChannelHandlerContext ctx) throws Exception {

ByteBuf buf = internalBuffer();

int readable = buf.readableBytes();

if (readable > 0) {

ByteBuf bytes = buf.readBytes(readable);

buf.release();

ctx.fireChannelRead(bytes);

ctx.fireChannelReadComplete();

} else {

buf.release();

}

cumulation = null;

handlerRemoved0(ctx);

}

该方法主要的实现思路是,如果内部的累积缓存区可读,则需要将剩余的字节处理,然后释放内部累积缓存区,并设置为空,然后提供一个钩子函数,供子类去实现。handlerRemoved0(ctx)。

2.2.2 channelRead 通道读事件

@Override

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

if (msg instanceof ByteBuf) { //@1

RecyclableArrayList out = RecyclableArrayList.newInstance(); //@2

try {

ByteBuf data = (ByteBuf) msg;

first = cumulation == null; //@3

if (first) {

cumulation = data;

} else {

cumulation = cumulator.cumulate(ctx.alloc(), cumulation, data); //@4

}

callDecode(ctx, cumulation, out); //@5

} catch (DecoderException e) {

throw e;

} catch (Throwable t) {

throw new DecoderException(t);

} finally {

if (cumulation != null && !cumulation.isReadable()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值