【源码剖析】Netty 服务端 请求处理 详解

shadowLogo

前言:

在之前的博文中,本人讲解了 Netty服务端启动流程核心源码

那么,在本篇博文中,本人就来讲解下 Netty服务端请求处理核心源码


连接请求 的 处理:

假设这一时刻,有 客户端连接请求 过来了
就会调用本人上文所讲的 processSelectedKey方法 的逻辑:
连接事件


我们跟进去:

处理连接 —— read方法:

建立连接

读取消息

我们可以看到:

此方法中:

  • readBuf 作为 参数,调用了 doReadMessages方法
  • readBuf 中的每一个 NioSocketChannel,都调用了 NioServerSocketChannelpipeline 中的 每一个HandlerchannelRead处理逻辑

(由于当前状态,是 通道初始化完毕
因此 NioServerSocketChannelpipeline结构 如下:
结构
)


我们继续跟进去:

建立连接 —— doReadMessages方法:

建立连接
我们可以看到:

内部执行逻辑,只是:

  • 客户端 建立 连接通道
  • 上一步建立的 连接通道,封装成 NioSocketChannel 类型,放入 readBuf

我们来看看上图中 SocketUtils.accept方法实现逻辑

NIO 原生API调用 —— SocketUtils.accept方法:

原生
我们可以看到:

此方法 中,调用了 NIO原生API,实现了 与客户端 连接通道建立


那么,我们再来看看,封装ChannelNioSocketChannel 双参构造器,实现了 什么逻辑:

封装Channel —— NioSocketChannel 双参构造:

调用
跟进 父类构造器
父类构造器

我们可以看到:

此方法,同样调用了 父类构造器
但是,第三个参数,是 NIO原生API读事件注册Key

想必之后的逻辑,会对当前建立的通道,注册 读事件

我们继续跟进:
属性赋值
我们可以看到:

内部执行逻辑,只是:

  • 与客户端建立的通道,赋值给 ch属性
  • 读事件注册Key,赋值给 readInterestOp属性
  • 设置 当前通道非阻塞

但是,并没有,注册 读事件

在下文中,会使用到 本方法设置的 两个成员属性,来 注册通道对应事件


连接建立 完毕 之后,我们来看看还执行了什么逻辑:

channelRead逻辑调用 —— invokeChannelRead方法:

参数
我们可以看到:

内部执行逻辑,只是:

  • 调用 AbstractChannelHandlerContextinvokeChannelRead方法
    自身参数,就是 调用 invokeChannelRead方法第二参数
    (也就是说:所传参数,就是 channelRead处理逻辑,所 读取到的 msg)

那么,我们继续跟下去,来验证下本人的讲解:
封装
我们继续跟下去:
调用
可以看到:

在本方法中,以 责任链模式,调用了 pipeline 中的 所有处理器channelRead方法

验证了本人的讲解!


因此,接下来会以 加入 readBufNioSocketChannel 作为 msg
(是的,你没有看错,就是以 NioSocketChannel 作为 msg),
调用 ServerBootstrapAcceptorchannelRead方法
read逻辑

我们可以看到:

内部执行逻辑,只是:

  • 将 之前用户自定义ChannelInintializer处理器逻辑,加入 每一个与客户端建立的 NioSocketChannelpipeline
  • workerGroup注册 所有NioSocketChannel

当前方法执行完毕后,相应的 NioSocketChannelpipeline 就会变为 如下格式
socketChannel
(注意:此时,所有NioSocketChannel 均未初始化,之前 初始化过 的只是 NioServerSocketChannel)


注册通道:

至于 NioSocketChannel 是如何 注册到 workerGroup 上的,
和之前博文《【源码剖析】Netty 服务端 启动流程 详解》中,向 bossGroup 注册 ServerSocketChannel 通道 的逻辑,是基本上一样的

本人就不重复进行讲解了,只是简单说下 实现逻辑
实现逻辑

  • NioSocketChannel 注册到 workerGruop任一NioEventLoop 上的 Selector
    注册事件读事件
  • 将 用户通过 childHandler方法 传入的 ChannnelInintializer 中的 initChannel方法 的逻辑,也执行一遍
    (一般都是 向 NioSocketChannel 中的 pipeline 中 添加 新的Handler)
    并将 ChannnelInintializerpipeline移除

最终,每一个 NioSocketChannel 中的 pipeline结构 如下:
结构


客户端消息 的 处理:

假设这一时刻,有 客户端消息 过来了
还是会调用本人上文所讲的 processSelectedKey方法 的逻辑:
消息


那么,我们继续跟进去,就会发现:

连接事件消息处理事件read方法 实现类 不一样

处理消息 —— read方法:

消息处理
我们可以看到:

内部执行逻辑,只是:

  • 申请 缓冲区 空间
  • 客户端数据 读入 byteBuf
  • 责任链模式,调用 用户自定义处理器channelReadchannelReadComplete 的逻辑

那么,本人再来讲解下 doReadBytes方法执行逻辑

消息读取 —— doReadBytes方法:

api
我们可以看到:

内部执行逻辑,只是:

  • 调用 ByteBufAPI,通过 NioSocketChannelChannel
    客户端消息 读入 ByteBuf

至此,Netty服务端请求处理核心源码,就讲解完毕了!

结束

posted @ 2021-05-08 19:15  在下右转,有何贵干  阅读(303)  评论(0编辑  收藏  举报