初识Netty——服务端、客户端创建

 Netty服务端创建

先来看server bootstrap:是socket服务端的启动辅助类,用户通过它可以方便的创建netty的服务端

 Netty服务端创建的步骤:

  1. 创建server bootstrap实例
  2. 设置并绑定reactor线程池。Netty 的 Reactor 线程池是 EventLoopGroup,它实际就是 EventLoop 的数组。EventLoop 的职责是处理所有注册到本线程多路复用器Selector 上的Channel,Selector 的轮询操作由绑定的 EventLoop 线程 run 方法驱动,在一,个循环体内循环执行。
  3. 设置并绑定服务端channel,作为NIO服务端,需要创建serversocketchannel,对应netty实现为Nioserver socket channel。Serverbootstrap也提供了channel方法用于指定服务端channel的类型,netty通过工厂类,利用反射创建Nioserver socket channel对象

  1. 创建channelpipeline,本质是一个负责处理网络事件的职责链,负责执行channel handler
  2. 往Channelpipeline中添加channel handler
  3. 绑定并监听启动端口
  4. Selector轮询。由Reactor 线程NioEventLoop 负责调度和执行Selector 轮询操作,选择准备就绪的Channel集合
  5. 当轮询到就绪的channel之后,就由reactor线程NioEventloop执行channelpipeline的相应方法,最终执行channelhandler
  6. 执行channelhandler和用户添加的handler

Netty服务端创建源码分析

首先通过构造函数创建server bootstrap实例,创建两个Event loop group

NioEventLoopGroup 实际就是 Reactor 线程池,负责调度和执行客户端的接入、网络读写事件的处理、用户自定义任务和定时任务的执行。通过ServerBootstrap的 group方法将两个EventLoopGroup实例传入

创建Nioserversocketchannel,根据channel类型通过反射创建channel实例

服务端启动的最后一步就是绑定本地端口,启动服务

Nioserversocketchannel创建成功后,对他进行初始化

第一步设置socket参数和channel的附加属性

第二步将handler加入到channelpipeline中

之后最后一步就是注册Nioserversocketchannel到reactor线程的多路复用器上

先看看目前channelpipeline的组成

到这里服务端启动部分源码已经分析完成

 客户端接入源码

当多路复用器检测到新的准备就绪的Channel时,默认执行 processSelectedKeysOptimized 方法

由于监听的是客户端那边的连接操作,所以执行Unsafe.read()方法

分析domessage方法,实际上就是接受新的客户端连接并创建Niosocketchannel

接受新的客户端连接后,触发channelpipeline的channelread方法

Niosocketchannel的注册方法与server socket channel的一致,也是将channel注册到reactor线程的多路复用器上

执行完注册操作之后,紧接着会触发ChanncelReadComplete 事件。我们继续分析ChannelReadComplete 在ChannelPipeline 中的处理流程:Netty 的Header 和Tail 本身不关注 ChannelReadComplete 事件就直接透传,执行完ChannelIReadComplete 后,接着执行,PipeLine 的 read()方法,最终执行HeadHandler的 read()方法HeadHandlerread()方法的代码已经在之前的小节介绍过,用来将网络操作位修改为操作。创建 NioSocketChannel 的时候已经将AbstractNioChanncl 的 readInterestOp 设置为OP_READ,这样,执行 selectionKey.interestOps(interestOpslreadInterestOp)操作时就会把操作位设置为OP_READ

至此,新接入的客户端连接处理完成,可以进行读写

 客户端创建

Bootstrap是客户端创建工具类

Netty客户端创建流程:

步骤1:用户线程创建Bootstrap实例,通过API设置创建客户端相关的参数,异步发起客户端连接

步骤2:创建处理客户端连接、I/O读写的Reactor 线程组NioEventLoopGroup。可以通过构造函数指定I/O线程的个数,默认为CPU 内核数的2倍;

步骤3:通过 Bootstrap的ChanneIFactory 和用户指定的Channel类型创建用于客户端连接的NioSocketChannel,它的功能类似于JDKNIO类库提供的SocketChannel

步骤4:创建默认的Channel HandlerPipeline,用于调度和执行网络事件;

步骤5:异步发起TCP连接,判断连接是否成功。如果成功,则直接将NioSocketChannel注册到多路复用器上,监听读操作位,用于数据报读取和消息发送;如果没有立即连接成功,则注册连接监听位到多路复用器,等待连接结果;

步骤6:注册对应的网络监听状态位到多路复用器;

步骤7:由多路复用器在I/O现场中轮询各Channel,处理连接结果;

步骤8:如果连接成功,设置Future 结果,发送连接成功事件,触发 ChanneIPipcline执行;

步骤9:由ChanneIPipeline 调度执行系统和用户的ChanneIHandler,执行业务逻辑

Boostrap提供了设置IO线程组的接口:

TCP参数设置接口:

Channel接口:用于指定客户端使用的channel接口(反射机制)

设置handler接口:

发起客户端连接:

 客户端连接操作

首先要创建和初始化Niosocketchannel

从NioEventLoopGroup中 获 取 NioEventLoop,然后使用其作为参数创建NioSocketChannel

初始化channel后,将其注册到selector上

发起异步TCP连接

Doconnect0最终调用head handler的connect方法

需要注意的是,SocketChannel 执行 connect()操作后有以下三种结果:(1)连接成功,返回True(2)暂时没有连接上,服务端没有返回ACK 应答,连接结果不确定,返回False;(3)连接失败,直接抛出I/O异常。如 果 是 第 二 种 结 果,需 要 将NioSocketChannel 中 的 selectionKey 设 置 为OP_ CONNECT,监听连接结果。异步连接返回之后,需要判断连接结果,如果连接成功,则触发 ChannelActive事件

ChanelActive 事件最终会将 NioSocketChannel 中的 selectionKey 设置为SelectionKey.OP_READ,用于监听网络读操作。如果没有立即连接上服务端,则注册 SelectionKey.OP_CONNECT 到多路复用器

如果过程发生异常,则关闭链路

 异步连接结果通知

当服务端返回握手应答之后,对连接结果进行判断

进一步看finishconnect方法:

Dofinishconnect方法用于判断JDK的socketChannel的连接结果

连接成功之后调用fulfillconnectPromiose方法,触发链路激活事件

Fire Channel Active方法主要修改网络监听位为读操作

 客户端连接超时机制

首先,用户在创建Netty客户端的时候,可以通过ChannelOption.CONNECT TIMEOUT_MILIS配置项设置连接超时时间

发起连接的同时,启动连接超时检测定时器

如果在超时之前获取到结果,就删除定时器

无论是否连接成功,只要获取到结果,就删除连接超时定时器

  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值