[编织消息框架][netty源码分析]5 EventLoopGroup 实现类NioEventLoopGroup职责与实现
分析NioEventLoopGroup最主有两个疑问
1.next work如何分配NioEventLoop
2.boss group 与child group 是如何协作运行的
从EventLoopGroup接口约定通过register方法从channel或promise转换成ChannelFuture对象
next方法就是用来分配NioEventLoop
public interface EventLoopGroup extends EventExecutorGroup { @Override EventLoop next(); ChannelFuture register(Channel channel); ChannelFuture register(ChannelPromise promise); @Deprecated ChannelFuture register(Channel channel, ChannelPromise promise); }
为了节省篇副,做了代码整理
1.NioEventLoopGroup构造时绑定SelectorProvider.provider(),通过newChild生成单个EventLoop
2.next实现是个环形循环
3.register方法是将channel转换成ChannelFuture
读者如果感兴趣可以在这几个方法打上断点看看
public class NioEventLoopGroup extends MultithreadEventLoopGroup { public NioEventLoopGroup(int nThreads, Executor executor) { this(nThreads, executor, SelectorProvider.provider()); } @Override protected EventLoop newChild(Executor executor, Object... args) throws Exception { return new NioEventLoop(this, executor, (SelectorProvider) args[0], ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]); } /////////////////////////////GenericEventExecutorChooser实现next////////////////////////////////// @Override public EventExecutor next() { return executors[Math.abs(idx.getAndIncrement() % executors.length)]; } /////////////////////////////SingleThreadEventLoop实现register////////////////////////////////// @Override public ChannelFuture register(Channel channel) { return register(new DefaultChannelPromise(channel, this)); } @Override public ChannelFuture register(final ChannelPromise promise) { ObjectUtil.checkNotNull(promise, "promise"); promise.channel().unsafe().register(this, promise); return promise; } }
我们用过程的方式来模拟NioEventLoopGroup使用
如果读者有印象netty server 至少有两组NioEventLoopGroup 一个是boss 另一个是child
public class TestBossChildGroup { static SocketAddress address = new InetSocketAddress("localhost", 8877); @Test public void server() throws IOException { SelectorProvider bossProvider = SelectorProvider.provider(); SelectorProvider childProvider = SelectorProvider.provider(); int count = 2; AbstractSelector bossSelector = bossProvider.openSelector(); AbstractSelector[] childSelectors = new AbstractSelector[count]; for (int i = 0; i < count; i++) { childSelectors[i] = childProvider.openSelector(); } //server绑定访问端口 并向Selector注册OP_ACCEPT ServerSocketChannel serverSocketChannel = bossProvider.openServerSocketChannel(); serverSocketChannel.configureBlocking(false); serverSocketChannel.bind(address); serverSocketChannel.register(bossSelector, SelectionKey.OP_ACCEPT); int i = 0; while (true) { int s = bossSelector.select(300); if (s > 0) { Set<SelectionKey> keys = bossSelector.selectedKeys(); Iterator<SelectionKey> it = keys.iterator(); while (it.hasNext()) { SelectionKey key = it.next(); //为什么不用elseIf 因为 key interestOps 是多重叠状态,一次返回多个操作 if (key.isAcceptable()) { System.out.println("isAcceptable"); //这里比较巧妙,注册OP_READ交给别一个Selector处理 key.channel().register(childSelectors[i++ % count], SelectionKey.OP_READ); } //这部分是child eventLoop处理 if (key.isConnectable()) { System.out.println("isConnectable"); } if (key.isWritable()) { System.out.println("isWritable"); } if (key.isReadable()) { System.out.println("isReadable"); } key.interestOps(~key.interestOps()); it.remove(); } } } } @Test public void client() throws IOException { SocketChannel clientSocketChannel = SelectorProvider.provider().openSocketChannel(); clientSocketChannel.configureBlocking(true); clientSocketChannel.connect(address); } }
作者: | solq |
博客地址: | http://www.cnblogs.com/solq111 |
博客版权: | 本文以学习、研究和分享为主,欢迎转载,但必须在文章页面明显位置给出原文连接。 如果文中有不妥或者错误的地方还望高手的你指出,以免误人子弟。如果觉得本文对你有所帮助不如【推荐】一下!如果你有更好的建议,不如留言一起讨论,共同进步! 再次感谢您耐心的读完本篇文章。 淘宝店: 海豚极货店 QQ群:9547527 |
如果你热爱生活、热爱编程、热爱吉他。扫一扫加我微信 |
我的新书《编织消息框架》目前进行中,感谢大家关注! |
本作品采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议进行许可。 |