源码跟踪结论:boss线程只是接收客户端socket并初始化客户端channle,,将channel注册到worker线程中。boss中不会做耗时的I/O读取,只是将channel丢给worker。
以下为我进行的代码追踪过程:
--->NettyServer.doOpen()
--->ServerBootstrap.bind(final SocketAddress localAddress)
--->ServerBootstrap.bindAsync(final SocketAddress localAddress)
--->NioServerSocketChannelFactory.newChannel(ChannelPipeline pipeline)
--->NioServerSocketChannel(
ChannelFactory factory,
ChannelPipeline pipeline,
ChannelSink sink, Boss boss, WorkerPool<NioWorker> workerPool)构造函数
--->ServerSocketChannel.open()//打开ServerSocketChannel
……
--->NioServerSocketPipelineSink.eventSunk
---> NioServerSocketPipelineSink.handleServerSocket(e)
--> NioServerBoss------------boss的任务从这里开始
--->(NioServerBoss) channel.boss). bind(final NioServerSocketChannel channel, final ChannelFuture future,final SocketAddress localAddress)//这里boss就是初始化时将doOpen中的那一个boss赋值在了NioServerSocketChannel中,也就是下面调bind方法就是doOpen那边设置的boss去执行的
--->AbstractNioSelector.registerTask(new RegisterTask(channel, future, localAddress))
--->RegisterTask.run()
--->channel.socket.socket().bind(localAddress, channel.getConfig().getBacklog())//绑定address
--->channel.socket.register(selector, SelectionKey.OP_ACCEPT, channel);// 将这个通道channel注册到指定的selector中,返回一个SelectionKey对象实例。其实就是将serversocket注册到一个selector里面,实现NIO的异步IO处理 注:OP_ACCEPT:服务端请求连接客户端。
---> 调用AbstractNioSelector.registerTask ---selector.wakeup();//唤醒线程
---> AbstractNioSelector.run()
---> AbstractNioSelector.select(selector)// 可以选择已经准备就绪的通道,返回的int值表示有多少通道已经就绪 。比如对读就绪的通道感兴趣,那么select()方法就会返回读事件已经就绪的那些通道。
---> AbstractNioSelector.processTaskQueue();//是从taskQueue里面取任务,taskQueue里面取出来的是selector和ServerSocketChannel 以及某事件绑定的Runnable。
---> NioServerBoss.process(selector)// 在process方法里面是一个死循环,里面在不间断的等待客户端的连接,如果有客户端的连接,那么将会调用方法registerAcceptedChannel进行后续的处理。
---> NioServerBoss.process ----SelectionKey.attachment();//取出
channel.socket.register(selector, SelectionKey.OP_ACCEPT, channel)中的channel 注:channel是NioServerSocketChannel对象,其中的参数有ServerSocketChannel socket;Boss boss;WorkerPool<NioWorker> workerPool;ServerSocketChannelConfig config;
---> NioServerBoss.process ---channel.socket.accept();//监听新进来的连接
当 accept()方法返回的时候,它返回一个包含新进来的连接的 SocketChannel。因此, accept()方法会一直阻塞到有新连接到达,Java NIO中的 ServerSocketChannel 是一个可以监听新进来的TCP连接的通道。
---> NioServerBoss.process ---registerAcceptedChannel(channel, acceptedSocket, thread)// 将新的连接注册到worker线程,让worker线程负责后续读写
--->到此boss的任务就结束了,boss主要用来监听socket请求,并把客户端的channel分发给worker去执行
即doOpen中的worker最后赋值给了AbstractNioWorkerPool中的workerExecutor变量,NioWorkerPool继承了AbstractNioWorkerPool,所以也可以调到workerExecutor变量。workers中存放 worker线程,即worker相当于doOpen中的worker,只不过workers为线程组。
bossExecutor值就是doOpen中的worker线程组,bosses存放的也是doOpen中的worker线程。NioServerBossPool继承AbstractNioBossPool,所以NioServerBossPool也可以调用这几个参数
最终NioServerSocketChannelFactory中存放了doOpen中的worker和boss
所以最后等于把doOpen中的那一个boss线程和worker组放在了NioServerSocketChannel
这里就是 boss初始化时做的事情