前言
netty学习系列笔记总结,服务端启动流程源码浅析,错误之处欢迎指正, 共同学习
服务端启动代码示例
1 | EventLoopGroup bossGroup = new NioEventLoopGroup(1); |
服务端Channel的创建
- 创建底层JDK Channel
- 封装JDK Channel
- 创建基本组件绑定Channel;
1.bind(port)[用户代码入口]:serverBootstrap.bind(port)
1 | // Configure the server. |
2.initAndRegister()[初始化并注册]
1 | final ChannelFuture initAndRegister() { |
3.newChannel()[创建服务端Channel]
通过serverBootstrap.channel()方法传入NioServerSocketChannel类,构造ReflectiveChannelFactory实例将NioServerSocketChannel类设置为反射类; channelFactory.newChannel()通过clazz.newInstance()调用反射类构造方法反射创建服务端Channel
4.channelFactory在哪里初始化?
1 | //首先channelFactory在开篇示例代码b.channel(NioServerSocketChannel.class)中被设置成new ReflectiveChannelFactory<C>(NioServerSocketChannel.class) |
5.通过JDK底层创建socketChannel(服务端Channel创建过程)
- 反射创建服务端Channel:NioServerSocketChannel默认构造方法调用newSocket()使用provider.openServerSocketChannel()创建服务端Socket
1
2
3
4
5
6
7
8
9
10
11
12
13
14private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
public NioServerSocketChannel() {
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
//在newSocket()中创建了开篇提到的监听套接字ServerSocketChannel
private static ServerSocketChannel newSocket(SelectorProvider provider) {
try {
return provider.openServerSocketChannel();
} catch (IOException e) {
throw new ChannelException("Failed to open a server socket.", e);
}
}
6.NioServerSocketChannelConfig()[TCP参数配置类]:设置底层JDK Channel TCP参数配置
1 | //SelectionKey.OP_ACCEPT标志就是监听套接字所感兴趣的事件了(但是还没注册进去) |
7.configureBlocking(false)[阻塞模式]:设置非阻塞模式
1 | //NioServerSocketChannel父类构造函数 |
8.AbstractChannel()[创建id,unsafe,pipeline]
1 | //继续父类构造方法 |
服务端Channel的初始化
- init()[初始化服务端channel,初始化入口]
- set ChildOptions,ChildAttrs:提供给通过服务端Channel创建的新连接Channel,每次accept新连接都配置用户自定义的两个属性配置
- config handler[配置服务端Pipeline]
- add ServerBootstrapAcceptor[添加连接器]:提供给accept接入的新连接分配NIO线程
- 保存用户自定义基本属性,通过配置属性创建连接接入器,连接接入器每次accept新连接使用自定义属性配置新连接
1 | //1.设置NioServerSocketChannel的options和attrs. |
注册Selector
将底层JDK Channel注册到事件轮询器Selector上面,并把服务端Channel作为Attachment绑定在对应底层JDK Channel
AbstractChannel.register(channel)[注册Selector入口]
doRegister()
调用JDK底层注册:JDK Channel注册Selector调用javaChannel().register(eventLoop().selector, 0, this),将服务端Channel通过Attachment绑定到Selector
invokeHandlerAddedIfNeeded():事件回调,触发Handler
fireChannelRegistered()[传播事件]
1 | public final void register(EventLoop eventLoop, final ChannelPromise promise) { |
register0()
1 | private void register0(ChannelPromise promise) { |
doRegister()
1 | //javaChannel().register(), 这里先把interestOps注册为0 |
服务端口的绑定
AbstractUnsafe.bind()[端口绑定]
doBind():javaChannel().bind()[JDK动态绑定]
pipeline.fireChannelActive()[传播事件]:HeadContext.readIfIsAutoRead()将注册Selector的事件重新绑定为OP_ACCEPT事件,有新连接接入Selector轮询到OP_ACCEPT事件最终将连接交给Netty处理
绑定OP_ACCEPT事件:当端口完成绑定触发active事件,active事件最终调用channel的read事件,read对于服务器来说可以读新连接
1 | private ChannelFuture doBind(final SocketAddress localAddress) { |
AbstractChannel
1 | public final void bind(final SocketAddress localAddress, final ChannelPromise promise) { |
NioServerSocketChannel
1 | protected void doBind(SocketAddress localAddress) throws Exception { |
AbstractNioChannel端口绑定成功,告诉selector需要关心accept事件
1 | protected void doBeginRead() throws Exception { |
总结
Netty服务端启动:
创建服务端Channel:创建底层JDK Channel,封装JDK Channel,创建基本组件绑定Channel;
初始化服务端Channel:设置Channel基本属性,添加逻辑处理器;
注册Selector:将底层JDK Channel注册到事件轮询器Selector上面,并把服务端Channel作为Attachment绑定在对应底层JDK Channel;
端口绑定:实现本地端口监听,绑定成功重新向Selector注册OP_ACCEPT事件接收新连接
服务端Socket在哪里初始化?
反射创建服务端Channel:NioServerSocketChannel默认构造方法调用newSocket()使用provider.openServerSocketChannel()创建服务端Socket
在哪里accept连接?
端口绑定:Pipeline调用fireChannelActive()传播active事件,HeadContext使用readIfIsAutoRead()重新绑定OP_ACCEPT事件,新连接接入Selector轮询到OP_ACCEPT事件处理