netty服务端处理流程
构建ServerBootStrap对象;
1、设置服务端连接参数;
2、设置EventLoopGroup对象,用以处理服务段请求;
NioEventLoopGroup可以设置多个线程,每个线程对应一个NioEventLoop对象用以处理请求;NioEventLoop实例分两类,一类bind服务地址,accept远程请求连接event,称为boss组,一类处理请求的数据并返回响应数据event,称为worker组;可以只创建一个group,两类NioEventLoop实例公用,也可以分别创建boos和worker组,分别处理两类事件,避免数据处理太耗时NioEventLoop实例被占用而无发接收请求。此外为主监听channel和子处理channel设置参数。
bossGroup负责接收连接,为每一个连接创建从线程,不仅接收也处理;
workGroup负责连接的i/o操作,为每个请求创建处理线程;
4、设置childHandler对象值(channel初始化handler);
初始化请求数据处理的channel ChannelPipeline里的handler list;请求数据处理被分隔成一个个part,每个part由对应的handler处理,形成数据处理的strem流。
5、channelFactory设置
本例为NioServerSocketChannel,用来创建channel
6、ServerBootStrap bind服务地址
6.1创建ServerSocketChannel
根据channelFactory设置的channel类,创建对应的类NioServerSocketChannel实例;
NioServerSocketChannel实例会创建一个ServerSocketChannelImpl实例来初始化SelectableChannel ch变量;
private static ServerSocketChannel newSocket(SelectorProvider provider) {
try {
/**
* Use the {@link SelectorProvider} to open {@link SocketChannel} and so remove condition in
* {@link SelectorProvider#provider()} which is called by each ServerSocketChannel.open() otherwise.
*
* See <a href="https://github.com/netty/netty/issues/2308">#2308</a>.
*/
return provider.openServerSocketChannel();
} catch (IOException e) {
throw new ChannelException(
"Failed to open a server socket.", e);
}
}
private final ServerSocketChannelConfig config;
/**
* Create a new instance
*/
public NioServerSocketChannel() {
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
6.2地址绑定
将ServerSocketChannel中的监听句柄fd绑定到服务地址上;
ServerBootStrap调用bind()方法,在bind()方法中会创建NioServerSocketChannel对象,并将NioServerSocketChannel对象中的ServerSocketChannel对象(SelectableChannel ch变量,监听sockets)注册给boos group里的某个EventLoop对象里的Selector变量,并形成一个SelectionKey对象;
在ServerSocketChannel bind()方法中,将监听句柄fd 通过bind系统调用绑定到服务地址,然后通过listen系统调用让内核监听此句柄。
(注:这里bind过程中,一个监听channel只占boos group一个EventLoop线程,一般情况下boss group里一个线程就够了(main reactor通常只用到boos group线程组中的一个主要是因为Server只能绑定一个SocketAddress,并且只能绑定一次);如果bind多个地址,boss group可以设置多个线程,增加并发,bind多个地址可能需要代理服务器对外提供统一服务地址;还有一种说法是boos多线程做Auth/login/shake-hand/SLA用,没有时间过)。
在bind的过程中ServerSocketchannel会将SO_BACKLOG参数传给内核,用来限制内核连接ACCEPT队列的大小,当ACCEPT队列满了之后,内核网络服务会把SYN请求丢掉。内核网络会维持两个队列SYN和ACCEPT,当服务端接收到SYN请求后,会返回SYNACK,并将请求放入SYN队列,当3次握手完成后,将连接请求放入ACCEPT队列,然后通过accept()系统调用取出,供用户使用。
接下来,NioEventLoop task会不断地调用Slector 的select()方法,获取有i/o操作的channel。比如,NioServerSocketChannel对应的read事件,AbstractNioMessageChannel.NioMessageUnsafe.read()方法调用NioServerSocketChannel的doReadMessages()方法accept socket,并把对应的socketchannel给NioSocketChannel实例,由NioSocketChannel实例处理对应的请求。
请求服务
向netty服务器发送一个http请求,监听、创建注册对应的socket channel、io读写操作,这里最好debug调试。
在调试中可以看到NioServerSocketChannel有一个ServerSocketChannel对象,负责绑定服务地址,监听服务,NioSocketChannel有一个SocketChannel,负责请求i/o操作。