zoukankan      html  css  js  c++  java
  • Netty源码剖析-启动服务

    参考文献:极客时间傅健老师的《Netty源码剖析与实战》Talk is cheap.show me the code!

    --1主线分两步:

      一:首先在our thread里,如果写在main方法中则就是main thread;

    ①:创建selector;

    ②:创建server socket channel;

    ③:初始化server socket channel;

    ④:给server socket channel 从boss  group中选择一个NioEventLoop;

      二:boss thread:

    ⑤:将server socket channel注册到选择的NioEventLoop的selector(上一步创建的selector)

    ⑥:绑定地址启动

    ⑦:注册接收连接事件(OP_ACCEPT)到selector上

    --2源码演示:

      首先在代码启动的地方加断点,并且在NioEventLoop.java中的openSelector()上也加一个断点(用于验证selector什么时候被创建),如下图:

    Debug启动后会进入上图第一个断点,放行后进入openSelector()的这个断点上,通过观察Frames区域可以发现selector是在刚才第一个断点的时候就被创建了,即“EventLoopGroup bossGroup = new NioEventLoopGroup();”的时候:

    好的,继续放行之后则回来到开启服务的断点:

    不难看出有个sync(),它表示阻塞,也就是说启动本身是个异步的过程,.sync()代表要启动完才能进行下一步;接下来进入bind()方法看看,一直跟进,直到进入doBind();在如图的两个地方加上断点:

    上图的“final ChannelFuture regFuture = initAndRegister();”;initAndRegister()实际表示三步:①创建一个server socket channel,②初始化server socket channel,③将server socket channel注册到NioEventLoop的selector上。创建完成之后返回的是regFuture;通过名字“Future”就可以知道它是异步过程;所以上图第一个断点不一定能注册完成,因为注册是丢到NioEventLoop里面去执行去了,所以有个第二个断点:等着注册完成之后来通知再执行bind。然后我们跟进去看看initAndRegister():

    不难看出先通过工厂创建后初始化,接着跟进init(channel)方法:挨个下一步可以看到这段代码:

    这里的ChannelInitializer一次性,初始化hander,负责添加一个ServerBootstrapAcceptor hander,添加完成后自己就移除了,其中ServerBootstrapAcceptor hander负责接收客户端连接创建连接后,对连接的初始化工作。跳回去之后可以看到:

    "ChannelFuture regFuture = config().group().register(channel);"的group()就是boss group,跟进register()之后有这个代码,在图中的register0()这边加个断点:

    然后跟进eventLoop.execute()方法:

    接着进入startThread();

      走到这才是正正的启动线程,接着放行则会执行register0();

    再跟进register0()方法

    跟进doRegister():

    这里不难发现它真正在处理了,然后先跳回去,下面这图就是通知我们成功了

    继续往下走则会到之前打的一个断点(doBind0());

    然后继续跟进:

    在channel.bind()加一个断点:然后紧接着跳过来在进入bind()方法:

    可以看到pipeline.bind();Netty是串行化的操作,pipeline里面有各种各样的hander,除了上图截图显示的hander,每个pipeline都有head和tail 的hander;如下显示:

    这里我们跳到head的hander;操作如下:

    跳过来之后查找bind()方法如图,

    找到之后在unsafe.bind()加一个断点:

    跳过来进入bind()方法看看:

    可以看到这一步:do开头的几乎都是表示执行!在跟进去看看:

    这时候就能看到bind了,然后继续

    这里的就是绑定后开始激活,在pipeline.fireChannelActive()加一个断点,跳过来后:

    和之前一样,跳到head上;然后查找ChannelActive();

    打上断点如图,接着跳过来,其中readIfIsAutoRead()就是注册读事件,读包括:创建连接、读数据,这里指的是创建连接。跟进方法:

    继续跟进:

    能看出pipeline.read();这时候打开之前跳转过来的pipeline的head里找到read();

     加个断点接着跳过来,这里unsafe.beginRead();实际上就是注册OP_ACCEPT/OP_READ事件;创建连接或者读事件。接着跟进:

    实际它是调用的doBeginRead();

     继续跟进:

     走到这里就开始注册OP_ACCEPT=16。

    --3总结:启动服务的本质:

      Selector selector = sun.nio.ch.SelectorProviderImpl.openSelector();

      ServerSocketChannel serverSocketChannel = provider.openServerSocketChannel();

      selectionKey = javaChannel().register(eventLoop().unwrappedSelector(),0,this);

      javaChannel().bind(localAddress,config.getBacklog());

      selectionKey.interestOps(OP_ACCEPT);

    Selector是在new NioEventLoopGroup()(创建一批NioEventLoop)时创建的

    第一次Register并不是监听OP_ACCEPT,而是0;

      selectionKey = javaChannel().register(eventLoop().unwrappedSelector(),0,this);

    最终监听OP_ACCEPT是通过bind完成后的fireChannelActive()来触发的。

    NioEventLoop是通过Register操作的执行来完成启动的

    类似ChannelInitializer,一些Hander可以设计成一次性的,用完就移除,比如授权。

    我只想做的更好,仅此而已。

  • 相关阅读:
    Begin Example with Override Encoded SOAP XML Serialization
    State Machine Terminology
    How to: Specify an Alternate Element Name for an XML Stream
    How to: Publish Metadata for a WCF Service.(What is the Metadata Exchange Endpoint purpose.)
    Beginning Guide With Controlling XML Serialization Using Attributes(XmlSerializaiton of Array)
    Workflow 4.0 Hosting Extensions
    What can we do in the CacheMetaData Method of Activity
    How and Why to use the System.servicemodel.MessageParameterAttribute in WCF
    How to: Begin Sample with Serialization and Deserialization an Object
    A Test WCF Service without anything of config.
  • 原文地址:https://www.cnblogs.com/-qilin/p/11807450.html
Copyright © 2011-2022 走看看