[Netty]writeAndFlush全解析

作者:简书闪电侠
链接:https://www.jianshu.com/p/feaeaab2ce56

前言

在前面的文章中,我们已经详细阐述了事件和异常传播在netty中的实现,(netty源码分析之pipeline(一),netty源码分析之pipeline(二)),其中有一类事件我们在实际编码中用得最多,那就是 write或者writeAndFlush,也就是我们今天的主要内容

主要内容

本文分以下几个部分阐述一个java对象最后是如何转变成字节流,写到socket缓冲区中去的

  1. pipeline中的标准链表结构
  2. java对象编码过程
  3. write:写队列
  4. flush:刷新写队列
  5. writeAndFlush: 写队列并刷新

pipeline中的标准链表结构

一个标准的pipeline链式结构如下(我们省去了异常处理Handler)

标准的pipeline链式结构

数据从head节点流入,先拆包,然后解码成业务对象,最后经过业务Handler处理,调用write,将结果对象写出去。而写的过程先通过tail节点,然后通过encoder节点将对象编码成ByteBuf,最后将该ByteBuf对象传递到head节点,调用底层的Unsafe写到jdk底层管道

java对象编码过程

为什么我们在pipeline中添加了encoder节点,java对象就转换成netty可以处理的ByteBuf,写到管道里?

我们先看下调用write的code

BusinessHandler

 protected void channelRead0(ChannelHandlerContext ctx, Request request) throws Exception {
    Response response = doBusiness(request);
    
    if (response != null) {
        ctx.channel().write(response);
    }
 }

业务处理器接受到请求之后,做一些业务处理,返回一个Response,然后,response在pipeline中传递,落到 Encoder节点,下面是 Encoder 的处理流程

Encoder

public class Encoder extends MessageToByteEncoder<Response> {
    @Override
    protected void encode(ChannelHandlerContext ctx, Response response, ByteBuf out) throws Exception {
        out.writeByte(response.getVersion());
        out.writeInt(4 + response.getData().length);
        out.writeBytes(response.getData());
    }
}

Encoder的处理流程很简单,按照简单自定义协议,将java对象 Response 写到传入的参数 out中,这个out到底是什么?

为了回答这个问题,我们需要了解到 Response 对象,从 BusinessHandler 传入到 MessageToByteEncoder的时候,首先是传入到 write 方法

MessageToByteEncoder

@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
    ByteBuf buf = null;
    try {
        // 判断当前Handelr是否能处理写入的消息
        if (acceptOutboundMessage(msg)) {
            @SuppressWarnings("unchecked")
            // 强制换换
            I cast = (I) msg;
            // 分配一段ButeBuf
            buf = allocateBuffer(ctx, cast, preferDirect);
            try {
            // 调用encode,这里就调回到  `Encoder` 这个Handelr中    
                encode(ctx, cast, buf);
            } finally {
                // 既然自定义java对象转换成ByteBuf了,那么这个对象就已经无用了,释放掉
                // (当传入的msg类型是ByteBuf的时候,就不需要自己手动释放了)
                ReferenceCountUtil.release(cast);
            }
            // 如果buf中写入了数据,就把buf传到下一个节点
            if (buf.isReadable()) {
                ctx.write(buf, promise);
            } else {
            // 否则,释放buf,将空数据传到下一个节点    
            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值