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可以设计成一次性的,用完就移除,比如授权。
我只想做的更好,仅此而已。
Netty源码剖析-启动服务的更多相关文章
- Netty源码剖析-关闭服务
参考文献:极客时间傅健老师的<Netty源码剖析与实战>Talk is cheap.show me the code! ----主线: ----源码: 先在服务端加个断点和修改下代码:如 ...
- Netty学习笔记(三)——netty源码剖析
1.Netty启动源码剖析 启动类: public class NettyNioServer { public static void main(String[] args) throws Excep ...
- Netty源码剖析-发送数据
参考文献:极客时间傅健老师的<Netty源码剖析与实战>Talk is cheap.show me the code! 开始之前先介绍下Netty写数据的三种方式: ①:write:写到一 ...
- Netty源码剖析-业务处理
参考文献:极客时间傅健老师的<Netty源码剖析与实战>Talk is cheap.show me the code! ----主线:worker thread 触发pipeline.fi ...
- Netty源码剖析-接受数据
参考文献:极客时间傅健老师的<Netty源码剖析与实战>Talk is cheap.show me the code! ----主线:worker thread ①多路复用器(Select ...
- Netty源码剖析-构建链接
参考文献:极客时间傅健老师的<Netty源码剖析与实战>Talk is cheap.show me the code! ----主线: 和启动一样也是有两个线程完成的,boss threa ...
- Netty源码剖析-断开连接
参考文献:极客时间傅健老师的<Netty源码剖析与实战>Talk is cheap.show me the code! ----主线: ----源码: 在NioEventLoop的unsa ...
- 二 分析easyswoole源码(启动服务)
前文连接,阅读的时候最好参照EasySwoole2.1.2的源码 $inst->run();//启动服务 这里实际调用的是Core的start方法ServerManager::getInstan ...
- Netty 源码剖析之 unSafe.write 方法
前言 在 Netty 源码剖析之 unSafe.read 方法 一文中,我们研究了 read 方法的实现,这是读取内容到容器,再看看 Netty 是如何将内容从容器输出 Channel 的吧. 1. ...
随机推荐
- redis系列(二):数据操作
1.string类型 字符串类型是Redis中最为基础的数据存储类型,它在Redis中是二进制安全的,这便意味着该类型可以接受任何格式的数据,如JPEG图像数据或Json对象描述信息等.在Redis中 ...
- 动态拼接tr,th
var dltable=''; // <c:forEach items="data" var="data" ></c:forEach> ...
- Golang switch语句总结
switch 语句基本结构 switch 条件表达式 { case 常量表达式1: 语句 1 case 常量表达式2: 语句 2 . . . case 常量表达式n: 语句 n default: 语句 ...
- Flutter安装
下载右边的安装包以获取最新版本 stable 的 Flutter SDK 将压缩包解压,然后把其中的 flutter 目录整个放在你预想的 Flutter SDK 安装目录中(比如 C:\src\fl ...
- Git 中无法忽略 .xcuserstate 的解决方法
1.查看代码变化git status 2.接着输入 git rm –cached 刚才复制的地址 ,如下.git rm --cached RxSwift/Rx.xcodeproj/xcuserdata ...
- Leetcode题目300.最长上升子序列(动态规划-中等)
题目描述: 给定一个无序的整数数组,找到其中最长上升子序列的长度. 示例: 输入: [10,9,2,5,3,7,101,18] 输出: 4 解释: 最长的上升子序列是 [2,3,7,101],它的长度 ...
- WIN10环境下点击通知栏图标时自动切换输入法导致图标位置变动
这个问题由来已久,每当点击系统右下角任务栏中的按钮时,原本是搜狗输入法就会自动变成“US [ 中文(简体,中国) ]”,图标会自动错位,导致响应的是其他功能. 假设上图是正常的环境,此时我点击电池图标 ...
- XMLHttpRequest Level2 新功能
XMLHttpRequest是浏览器的接口,使得javascript可以进行HTTP(S)通信: 2008年2月,就提出了XMLHttpRequest Level 2 草案. 这个XMLHttpReq ...
- (一)OpenCV-Python学习—基础知识
opencv是一个强大的图像处理和计算机视觉库,实现了很多实用算法,值得学习和深究下. 1.opencv包安装 · 这里直接安装opencv-python包(非官方): pip install ope ...
- numpy中flatten学习笔记
ndarray.flatten() 用法 用于返回一个折叠成一维的数组.该函数只能适用于numpy对象,即array或者mat,普通的list列表是不行的. 例子 # coding=utf-8 fro ...