netty源码学习之服务端客户端初始化

​ 在之前的文章中我们学习了 netty的io模型netty的使用分析netty线程模型netty的ChannelPipeline类学习netty的ChannelPromise类学习。下面我们从使用netty例子出发探究一下netty的工作流程(其中包括服务端和客户端的创建、一次完整的请求和响应)。

1. AbstractBootstrap类简介

在探究netty一次请求的完整流程之前我们先来了解一下XXXBootstrap组件。 它是netty为我们提供的便于我们使用的工具启动类。他以builder的模式让我们可以简单设置例如channel、TCP参数、相关处理器。其中客户端使用Bootstrap类,服务端使用ServerBootstrap类两者的基类为AbstractBootstrap类。

在这里插入图片描述

1.1. 核心方法

AbstractBootstrap的

  • bind():netty服务端的与端口绑定,也是建立netty服务端的核心方法

Bootstrap的

  • connect():netty客户端与服务端进行连接,也是建立netty客户端的核心方法

补充说明:netty服务底层是使用NIO原理实现的,所以此处分析netty相关源码我们也分析到NIO层,至于NIO的底层原理实现请期待笔者后续的博文。

2. netty服务端创建

2.1. 服务端启动入口

​ netty服务端创建相关代码如下,服务端创建是使用bind()核心方法,下面来分析bind方法

//一、netty 服务端启动  
//.......省略ServerBootstrap构建过程
//绑定端口 netty服务端创建
ChannelFuture sync = serverBootstrap.bind(port).sync();
//服务监听端口关闭
sync.channel().closeFuture().sync();

bind()方法最终调用io.netty.bootstrap.AbstractBootstrap#doBind()方法,下面我们来分析netty服务端启动方法。

2.2. doBind()方法

private ChannelFuture doBind(final SocketAddress localAddress) {
   
    //正如其方法名一样 初始化channel,并进行channel和selector(多路复用器的注册绑定)
    //其返回值是netty自己封装的异步结果接口ChannelFuture
    final ChannelFuture regFuture = initAndRegister();
    final Channel channel = regFuture.channel();
    //如果异步结果中有异常则直接返回 此时:netty服务端初始化失败
    if (regFuture.cause() != null) {
   
        return regFuture;
    }

    final ChannelPromise promise;
    //上述的initAndRegister的结果是异步通知的 所有此处需要进行条件分支判断
    //如果上述操作已经完成(通道初始化完成)则直接进行doBind0()方法
    if (regFuture.isDone()) {
   
        promise = channel.newPromise();
        //channel和端口进行绑定操作
        doBind0(regFuture, channel, localAddress, promise);
    } else {
   
        //一般情况下initAndRegister会很快完成并给出结果 但是万一呢?
        promise = new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE);
        //此处针对如果上述未完成 添加一个事件监听,待上述操作完成后触发doBind0()
        regFuture.addListener(new ChannelFutureListener() {
   
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
   
                doBind0(regFuture, channel, localAddress, promise);
            }
        });
    }
    return promise;
}

netty服务端启动和绑定过程并不复杂主要分成了两部分(两个核心方法)

  • 初始化: initAndRegister方法,该方法主要功能是创建Channel对象(网络请求的数据流通道),并整合ServerBootstrap相关配置比如工作线程(NioEventLoopGroup)、option(参数配置)、attr(属性)、添加相关处理器(ChannelHandler),最后将多路复用器Selector注册到Channel。
  • 端口绑定:doBind0方法,该方法主要将端口和channel进行绑定。

2.3. netty服务初始化

2.3.1. initAndRegister()方法
final ChannelFuture initAndRegister() {
   
    Channel channel;
    try {
   
        //1、创建网络通道Channel
        channel = createChannel();
    } catch (Throwable t) {
   
        return VoidChannel.INSTANCE.newFailedFuture(t);
    }

    try {
   
        //2、为channel配置 线程、option、attr、事件处理器ChannelHandler
        init(channel);
    } catch (Throwable t) {
   
        channel.unsafe().closeForcibly();
        return channel.newFailedFuture(t);
    }

    ChannelPromise regFuture = channel.newPromise();
    //channel注册多路复用器selector
    channel.unsafe().register(regFuture);
    if (regFuture.cause() != null) {
   
        if (channel.isRegistered()) {
   
            channel.close();
        } else {
   
            channel.unsafe().closeForcibly();
        }
    }
    return regFuture;
}

netty服务端初始化也可以分成三部分

  1. 创建netty的channel对象,因为我们在构建的ServerBootstrap对象的时候调用了channel方法传入NioServerSocketChannel.class
//调用channel(NioServerSocketChannel.class)方法 会创建ServerBootstrapChannelFactory
return channelFactory(new ServerBootstrapChannelFactory<ServerChannel>(channelClass));

createChannel方法调用ServerBootstrapChannelFactory的newChannel(),通过反射调用NioServerSocketChannel的构造函数

//构建函数
public NioServerSocketChannel(EventLoop eventLoop, EventLoopGroup childGroup) {
   
    //父构造函数 newSocket()创建一个NIO的ServerSocketChannel 和eventLoop线程以及工作线程childGroup
    //包装成NioServerSocketChannel
    super(null, eventLoop, childGroup, newSocket(), SelectionKey.OP_ACCEPT);
    config = new DefaultServerSocketChannelConfig(this, javaChannel().socket());
}
  1. 初始化channel配置:init()方法整合ServerBootstrap相关配置比如工作线程(NioEventLoopGroup)、option(参数配置)、attr(属性)、添加相关处理器(ChannelHandler)并配置childHandler、currentChildOptions、currentChildAttrs包装成ServerBootstrapAcceptor
  2. channel注册selector:通过channel的unsafe对象(io.netty.channel.AbstractChannel.AbstractUnsafe)的register方法。
2.3.2. init()方法

​ 在上述方法的第二部分init()方法初始化channel配置最终实现类为io.netty.bootstrap.ServerBootstrap#init。

void init(Channel channel) throws Exception {
   
    //获取AbstractBootstrap的options(TCP配置信息) 设置到ChannelConfig中
    final Map<ChannelOption<?>, Object> options = options();
    synchronized (options) {
   
        channel.config().setOptions(options);
    }
    //获取AbstractBootstrap的attr属性 设置到Attribute中
    final Map<AttributeKey<?>
  • 34
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 24
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值