netty源码分析(七):netty编码和writeAndFlush

145 阅读2分钟

一.netty编码概述

我们发送数据时候,需要将java对象发送到网络前,需要把java对象编码成byteBuf,写入jdk底层的socket中,通过二进制数据,在网络中传输,把java对象转换为byteBuf过程就是编码

举例如下

public class MyEncode extends MessageToByteEncoder<Person> {
    @Override
    protected void encode(ChannelHandlerContext ctx, Person person, ByteBuf out) throws Exception {
        long length = person.getLength();
        out.writeShort((int) length);
        out.writeBytes(person.getName().getBytes());
    }
}
@Data
public class Person {
    private long length;
    private String name;
}

java对象Person只有简单的两个字段,第一个字段记录name的长度,第二个字段就是name的值

二.writeAndFlush步骤

在handler中发送数据,可以调用

ctx.writeAndFlush(person);

通过之前的讲解 # netty源码分析(五):pipline# 六.outboud事件传播 数据传播可以看到,会从当前handler节点往前找到outboud类型的handler,进行传播,会调用两个方法

- invokeWrite0(msg, promise);

- invokeFlush0();

1.invokeWrite0()方法会触发outboud类型的handler的write方法

在传播的过程中会调用到编码器的write方法,和上一篇文章编码器类似的,抽象父类[MessageToByteEncoder]也是个模板方法,会让不同的编码器子类去实现不同的编码

2.invokeFlush0()方法会触发flush方法

三.编码器MessageToByteEncoder

抽象父类,看witre方法

image.png

就会进入到我们自定义的编码器代码中

public class MyEncode extends MessageToByteEncoder<Person> {
    @Override
    protected void encode(ChannelHandlerContext ctx, Person person, ByteBuf out) throws Exception {
        long length = person.getLength();
        out.writeShort((int) length);
        out.writeBytes(person.getName().getBytes());
    }
}

会把当前对象person里面的值写入到ByteBuf中,继续往下传播,最终会调用到头结点

io.netty.channel.DefaultChannelPipeline.HeadContext
@Override
public void read(ChannelHandlerContext ctx) {
    unsafe.beginRead();
}

有前面的讲解可得知道,我们最终是unsafe类负责数据到写入和刷新, 继续进入

public final void write(Object msg, ChannelPromise promise) {
    assertEventLoop();

    ChannelOutboundBuffer outboundBuffer = this.outboundBuffer;
    if (outboundBuffer == null) {
        // If the outboundBuffer is null we know the channel was closed and so
        // need to fail the future right away. If it is not null the handling of the rest
        // will be done in flush0()
        // See https://github.com/netty/netty/issues/2362
        safeSetFailure(promise, WRITE_CLOSED_CHANNEL_EXCEPTION);
        // release message now to prevent resource-leak
        ReferenceCountUtil.release(msg);
        return;
    }

    int size;
    try {
        msg = filterOutboundMessage(msg);
        size = pipeline.estimatorHandle().size(msg);
        if (size < 0) {
            size = 0;
        }
    } catch (Throwable t) {
        safeSetFailure(promise, t);
        ReferenceCountUtil.release(msg);
        return;
    }

    outboundBuffer.addMessage(msg, size, promise);
}

四.写bugger队列

哎,好累啊...干不动了

五刷新队列