Netty之编码

目录

writeAndFlush

MessageToByteEncoder

head节点的write方法总结

head节点的flush方法总结


writeAndFlush

Netty写出数据是通过Outbound事件传播完成的,具体则是通过pipeline.writeAndFlush从tail节点开始依次向前传播,最后由head节点完成数据的写出与刷新。

writeAndFlush的传播过程:

  1. 从tail节点开始向前传播。
  2. 逐个调用channelHandler的write方法。
  3. 逐个调用channelHandler的flush方法。

MessageToByteEncoder

MessageToByteEncoder实现了ChannelOutboundHandlerAdapter接口,是Netty编码的最顶层抽象类,它将编码过程进行整体抽象,具体编码细节交给子类实现,通过pipeline传播Outbound事件。

整体过程可以分为以下六步:

  1. 数据匹配校验。
  2. 分配内存。
  3. 调用子类的编码实现。
  4. 释放原始对象。
  5. 传播ByteBuf直到head节点写出。
  6. 释放内存。
public abstract class MessageToByteEncoder<I> extends ChannelOutboundHandlerAdapter {
    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        ByteBuf buf = null;
        try {
            // 1.判断当前handler是否能处理这个数据对象
            if (acceptOutboundMessage(msg)) {
                @SuppressWarnings("unchecked")
                I cast = (I) msg;
                // 2.分配内存(优先分配direct内存)
                buf = allocateBuffer(ctx, cast, preferDirect);
                try {
                    // 3.进行具体编码操作,将编码后的对象填充到ByteBuf(由子类实现)
                    encode(ctx, cast, buf);
                } finally {
                    // 4.释放原始对象
                    ReferenceCountUtil.release(cast);
                }

                if (buf.isReadable()) {
                    // 5.传播ByteBuf,直到head节点
                    ctx.write(buf, promise);
                } else {
                    buf.release();
                    ctx.write(Unpooled.EMPTY_BUFFER, promise);
                }
                buf = null;
            } else {
                ctx.write(msg, promise);
            }
        } catch (EncoderException e) {
            throw e;
        } catch (Throwable e) {
            throw new EncoderException(e);
        } finally {
            // 如果出现异常,会释放资源
            if (buf != null) {
                buf.release();
            }
        }
    }
}

head节点的write方法总结

  1. 将heap内存转换成direct内存。
  2. 将要写出的数据加入到写缓冲区。
  3. 如果缓冲区超过一定容量,设置写状态为不可写,并将写状态事件传播给handler。

head节点的flush方法总结

  1. 添加刷新标志并更新写状态。
  2. 遍历Buffer队列,过滤ByteBuf。
  3. 调用JDK底层API进行自旋写。
发布了158 篇原创文章 · 获赞 109 · 访问量 21万+

猜你喜欢

转载自blog.csdn.net/u011212394/article/details/104034971