关于java:Netty七服务端读取数据流程-源码解读

2次阅读

共计 2298 个字符,预计需要花费 6 分钟才能阅读完成。

一、前言

上一章节中咱们介绍了服务端的启动流程,并且服务端接管到新连贯后,最终 提交【NioSocketChannel 注册】工作给 workerGroup 的 NioEventLoop

因为咱们 NioSocketChannel 对应的 ChannelPipeline 增加了一个 EchoServerHandler,所以此时 NioSocketChannel 对应的 ChannelPipeline 链是这样的:HeadContext -> EchoServerHandler -> TailContext,来看下 EchoServerHandler 的源码

public class EchoServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {ctx.write(msg);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // Close the connection when an exception is raised.
        cause.printStackTrace();
        ctx.close();}
}

接下来看下 workerGroup 的 NioEventLoop 是如何执行【NioSocketChannel 注册】工作的?

二、NioSocketChannel 注册

这里假设该 workerGroup 的 NioEventLoop 对应的线程名为 NioEventLoopGroup3-1。此时该 workerGroup 的 NioEventLoop 接管到了第一个工作, 开始进行初始化工作,启动线程并绑定,开始执行 NioEventLoop 类的 run 办法。run 办法的步骤之前已有介绍,这里不赘述。间接来看大抵流程图,如下

能够看到,在 runAllTasks 办法中来执行工作【NioSocketChannel 注册】,这里跟下面 NioServerSocketChannel 的注册调用的是同一个办法代码,大抵流程其实和【NioServerSocketChannel 注册】是一样的,然而有一个中央是不同的,就是 NioSocketChannel 的激活 之前 NioServerSocketChannel 的激活是独自提交一个工作 )。这里间接调用 DefaultChannelPipeline 的 fireChannelActive 办法,在 HeadContext 的 channelActive 办法中, 外部调用 readIfIsAutoRead()办法来设置 SelectionKey 的监听事件,NioSocketChannel 为 READ 事件

【NioSocketChannel 注册】工作执行实现之后,这时该 workerGroup 的 NioEventLoop 调用 Selector 的 select 办法进行阻塞,并监听该 NioSocketChannel 的 READ 事件。

三、读取客户端发送的数据

当接管到客户端发送过去的数据时,该 workerGroup 的 NioEventLoop 被唤醒,来看下 NioEventLoop 唤醒之后是如何读取数据的?

如上能够看到,当被唤醒之后会调用 NioByteUnsafe 的 read 办法,外部包含 4 个步骤:

  1. 调配 ByteBuf
  2. 调用 java nio 的 SocketChannel 的 read 办法 来读取数据
  3. 调用 DefaultChannelPipeline 的 fireChannelRead 办法,从 head 开始往后逐个调用 ChannelHandler 的 channelRead 办法,具体步骤如下

    能够看到先调用了 HeadContext 的 channelRead 办法,紧接着执行 EchoServerHandler 的 channelRead 办法,因为其外部执行 ctx.write 办法,所以会间接 回头调用 重写了 write 办法的 ChannelHandler,所以这里是调用 HeadContext 的 write 办法,其外部 调用了 ChannelOutboundBuffer 的 addMessage 办法,将数据增加到出站音讯的缓冲区中

  4. 调用 DefaultChannelPipeline 的 fireChannelReadComplete 办法,从 head 开始往后逐个调用 ChannelHandler 的 channelReadComplete 办法,具体步骤如下

    能够看到先调用了 HeadContext 的 channelReadComplete 办法,紧接着执行 EchoServerHandler 的 channelReadComplete 办法,因为其外部执行 ctx.flush 办法,所以会回头调用重写了 flush 办法的 ChannelHandler,所以这里调用 HeadContext 的 flush 办法,其 外部调用了 SocketChannel 的 write 办法,将数据写到客户端

四、小结

至此服务端读取客户端发送的数据的流程就完结了,从该源码中咱们能够看到 NioEventLoop 在其中表演了至关重要的角色,其 ChannelPipeline 的编排也是重要的拓展点,尽管这里咱们只是应用 EchoServerHandler 来演示流程,但理论开发中咱们能够通过增加各种自定义的 ChannelHandler 来实现不同的业务逻辑。

正文完
 0