bind函数_netty源码分析 第二节:bind函数启动过程

9a47b39c6fe241448c47e4f30f1795f7.png

从本节开始,跟踪ServerBootstrap的启动过程。服务端启动的第一步是先创建一个ServerSocketChannel,启动过程是由ChannelFuture f = b.bind(port).sync();bind函数触发的,下面详细分析其过程。

bind函数源码如下,代码位于ServerBootstrap的父类AbstractBootstrap中。

//AbstractBootstrap  


ServerBootstrap重写了父类AbstractBootstrap的validate,会先进入ServerBootstrap的validate函数,源码如下

//AbstractBootstrap  


先调用父类的validate,父类的validate函数逻辑较简单,就是判断父类维护的group和channelfactory是否为空,如果为空,抛出异常,都不为空,返回ServerBootstrap。
继续往下看,子类的validate函数会判断childHandler和childGroup是否为空,childHandler为空的时候回抛出异常,childGroup为空会使用ServerBootstrapConfig,也就是ServerBootstrap中的父类维护的group替代。
接着来看doBind的逻辑

//AbstractBootstrap

首先分析initAndRegister部分

//AbstractBootstrap


initAndRegister中主要有三大逻辑:
channelFactory.newChannel();创建ServerSocketChannel
init(channel); 初始化channel
config().group().register(channel);注册channel到Selector


接下来对这三个方法进行分析
1、首先分析channelFactory.newChannel()

channelFactory是AbstractBootstrap中维护的利用NioServerSocketChannel.class构建的,里面保存着class信息,查看下newChannel方法

//ReflectiveChannelFactory

利用反射,会依次加载NioServerSocketChannel的父类,初始化相关的静态变量,因为父类没有默认构造函数,所以调用了NioServerSocketChannel的默认构造函数。

//NioServerSocketChannel

会先调用内部的newSocket函数

//NioServerSocketChannel


可以看到这里调用SelectorProvider的openServerSocketChannel方法创建了一个ServerSocketChannel,这里就是ServerSocketChannel创建的地方。
接着进入NioServerSocket的另一个构造函数

public 


这里会调用父类的构造函数AbstractNioMessageChannel,AbstractNioMessageChannel构造函数调用了AbstractNioChannel的构造函数

//AbstractNioChannel


在这里ch.configureBlocking(false)设置了ServerSocketChannel为非阻塞的。this.readInterestOp = readInterestOp;设置了感兴趣的操作是accept。

super(parent);调用了父类AbstractChannel的构造函数

protected 


newUnsafe调用了子类AbstractNioMessageChannel的newUnsafe方法,创建了内部类NioMessageUnsafe。newChannelPipeLine调用了DefaultChannelPipeline的构造函数,并把NioServerSocketChannel传进去。DefaultChannelPipeline是一个管道,里面是一个以AbstractChannelHandlerContext为结点的双向链表,管道初始化了两个context,分别为head和tail。

至此,NioServerSocketChannel创建完毕。
2、init(channel)
源码如下

//ServerBootstrap


源码主要做了两件事:
1、把ServerBootstrap的父类AbstractBootstrap保存的options 和 attrs设置到NioServerSocketChannel中。
2、在NioServerSocketChannel的管道中增加ChannelInitializer,这是一个inboundhandler,增加以后,管道中变成head--》ChannelInitializer -- 》tail
匿名内部类中的initChannel方法重写了抽象类ChannelInitializer中的方法,这个方法在channelRegistered事件发生时,会被调用。
主要是在NioServerSocketChannel的管道中增加ServerBootstrapAcceptor,这也是一个Inboundhandler,保存了NioSocketChannel的相关参数。

//ChannelInitializer
//ChannelInitializer

3、config().group().register(channel)
实际是调用了NioEventLoopGroup的父类MultithreadEventLoopGroup的register方法。

//MultithreadEventLoopGroup


next方法从group中取得一个EventLoop,然后进入SingleThreadEventLoop的register方法进行注册。
在这个方法里,首先构造一个DefaultChannelPromise,里面封装了channel和线程,代表了该线程执行NioServerSocketChannel的结果,然后进入另外一个register方法。

//SingleThreadEventLoop


在这个方法里会进入AbstractUnsafe的register方法。源码如下

@Override
        


设置NioServerSocketChannel的eventLoop属性为传入的eventLoop,然后开启boss线程,把register0任务放入该线程的任务队列中。
我们接下来看下register0任务都做了什么:

private 


首先来看doRegister,doRegister是AbstractNioChannel中的方法

//AbstractNioChannel


注意这行:selectionKey = javaChannel().register(eventLoop().selector, 0, this);这里调用了ServerSocketChannel的register方法,注册到Selector中,并返回SelectionKey。这里是ServerSocketChannel注册到选择器的地方。

然后设置promise为success,这会触发在main线程中添加的listener,作用是调用doBind0方法,doBind0方法主要是添加bind任务到boss线程中。bind任务会在下节介绍。

//AbstractBootstrap


接着看pipeline.fireChannelRegistered方法,会触发channelRegisterd事件,跟踪源码,发现会依次调用head--》channelInitializer--》ServerBootstrapAcceptor--》tail。注意,在调用channelInitializer的fireChannelRegister的时候会initChannel,这个方法在之前介绍过,会增加ServerBootstrapAcceptor到pipeline中,然后删除自己。之后都没有做什么实质性的事情,最后以tail结束。

最后我们总结一下:

initAndRegister()方法主要做了以下几件事情:
1、 创建服务端监听套接字ServerSocketChannel
2、 设置监听套接字为非阻塞
3、 设置channel当前感兴趣的事件为SelectionKey.OP_ACCEPT(值为16)
4、 创建作用于ServerSocketChannel的管道Pipeline,该管道中此时的处理器链表为:Head(outbound)->tail(inbound)。
5、 设置NioServerSocketChannel的options和attrs,并存储之后用于SocketChannel的options和attrs
6、 为NioServerSocketChannel对应的管道增加一个Inbound处理器ChannelInitializer。经过此步骤后,管道中的处理器链表为:head(outbound)->ChannelInitializer(inbound)->tail(inbound)。注意ChannelInitializer的实现方法initChannel,里面会当channelRegisgered事件发生时将ServerBootstrapAcceptor加入到管道中。
7、 启动了boss线程,并将register0任务加入到boss线程的队列中。而register0做的事情为:将ServerSocketChannel、0、注册到selector中并得到对应的selectionkey。然后触发绑定端口的操作,将bind任务加入到boss线程的任务队列中,该内容在下一篇文章中分析。
8、通过channelRegistered事件,将ServerBootstrapAcceptor加入到管道中,并移除ChannelInitializer,经过此步骤后,管道中的处理器链表为:head(outbound)-> ServerBootstrapAcceptor (inbound)->tail(inbound)。
管道从创建到现在这段时间内,处理器链表的变化历史为:
head->tail
head->ChannelInitializer(inbound)->tail
head->ServerBootstrapAcceptor(inbound)->tail

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值