You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
return;
} catch (CancelledKeyException e) {
if (!selected) {
// Force the Selector to select now as the "canceled" SelectionKey may still be
// cached and not removed because no Select.select(..) operation was called yet.
eventLoop().selectNow();
selected = true;
} else {
// We forced a select operation on the selector before but the SelectionKey is still cached
// for whatever reason. JDK bug ?
throw e;
}
}
}
}
启动代码
分析代码
1. EventLoopGroup boss = new NioEventLoopGroup()
(1) EventLoopGroup可以认为是一个线程池或者线程组,此步创建父线程组,负责监听Channel事件,内部创建一个线程组数组,如果没有传入数组大小,数组大小默认为:
线程组数组大小取系统变量io.netty.eventLoopThreads和netty可用进程*2的较大值
(2) 创建线程组数组代码如下:
线程组数组为children = new EventExecutor[nThreads]
(3) 线程组数组中的值:children[i] = newChild(executor, args)
可见线程组数组中存的都是NioEventLoop,而NioEventLoop extends SingleThreadEventLoop,是只有一个活动线程的线程池
2. EventLoopGroup worker = new NioEventLoopGroup()
创建子线程组,负责处理Channel事件,实现同上。
其实NioEventLoopGroup中默认共有16个线程池,每个线程池是只有一个活动线程的NioEventLoop,NioEventLoop也是线程池,只是只有一个活动线程罢了。NioEventLoop会绑定到一个具体的Channel,负责整个Channel由生到死所有事件的处理,也就是一个Channel中的所有事件都由一个NioEventLoop的一个线程处理(NioEventLoop也只有一个线程)。NioEventLoop个数是固定的,但是客户端和服务端连接的Channel却有很多,所以一个NioEventLoop可以服务于很多个Channel。
3. ServerBootstrap bootstrap = new ServerBootstrap()
创建启动类
4. bootstrap.group(boss, worker)
设置父线程组和子线程组
5. bootstrap.channel(NioServerSocketChannel.class)
内部基于NioServerSocketChannel创建ChannelFactory,ChannelFactory可以生成NioServerSocketChannel
6. bootstrap.childHandler
添加handler处理具体的事件,netty内部具体什么时间将handler添加到ChannelPipeline中在后面的代码中
7. ChannelFuture future = bootstrap.bind(8866).sync()绑定端口
(1) 由port创建java.net.InetSocketAddress
(2) doBind绑定,其中 initAndRegister和doBind0最重要
(3) initAndRegister()分为init和register两步
init主要有两个功能:初始化Channel配置、将用户bootstrap.childHandler的事件添加到ChannelPipeline中
doRegister()方法可以由initAndRegister()一步步调试得到,javaChannel().register(eventLoop().unwrappedSelector(), 0, this)此处是将java.nio.channels.ServerSocketChannel注册到java.nio.channels.Selector上,已经调试到jdk的代码了
(4) doBind0()
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE)调用下面
如果jdk大于7,则通过java.nio.channels.ServerSocketChannel#bind(java.net.SocketAddress, int)方法绑定地址;否则通过java.net.ServerSocket#bind(java.net.SocketAddress, int)方法绑定地址。
8. future.channel().closeFuture().sync()
阻塞住当前线程直到服务器端监听端口关闭
作者原创,转载请注明出处,违法必究!
The text was updated successfully, but these errors were encountered: