文章目录
netty版本
- 使用的netty版本是
io.netty:netty-all:4.1.33.Final
NioServerSocketChannel的创建过程
- NioServerSocketChannel创建过程
无参构造方法的执行流程
-
构造方法
public NioServerSocketChannel() { this(newSocket(DEFAULT_SELECTOR_PROVIDER)); }
-
newSocket()
方法:这里为什么不用ServerSocketChannel.open()
来创建,而是使用缓存的SelectorProvider
?继续看下面分析private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider(); private static ServerSocketChannel newSocket(SelectorProvider provider) { try { return provider.openServerSocketChannel(); } catch (IOException e) { throw new ChannelException( "Failed to open a server socket.", e); } } //构造方法调用父类构造 public NioServerSocketChannel(ServerSocketChannel channel) { super(null, channel, SelectionKey.OP_ACCEPT); config = new NioServerSocketChannelConfig(this, javaChannel().socket()); }
构造方法调用父类的构造,设置感兴趣的事件
SelectionKey.OP_ACCEPT
,设置JDK底层的Channel
为非阻塞模式protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) { super(parent, ch, readInterestOp); } protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) { super(parent); this.ch = ch; this.readInterestOp = readInterestOp; try { ch.configureBlocking(false); } catch (IOException e) { try { ch.close(); } catch (IOException e2) { if (logger.isWarnEnabled()) { logger.warn( "Failed to close a partially initialized socket.", e2); } } throw new ChannelException("Failed to enter non-blocking mode.", e); } }
-
ServerSocketChannel
的open()
方法:每个新Channel
创建都需要SelectorProvider.provider()
(包含synchronized块)。 当应用程序创建大量连接时,这可能会导致不必要的阻塞。查看issuepublic static ServerSocketChannel open() throws IOException { return SelectorProvider.provider().openServerSocketChannel(); }
-
从构造方法中可以看到每个
NioServerSocketChannel
实例都关联一个NioServerSocketChannelConfig
,NioServerSocketChannelConfig
是TCP相关参数的配置,以及Netty中NioServerSocketChannel
相关的配置private final class NioServerSocketChannelConfig extends DefaultServerSocketChannelConfig { private NioServerSocketChannelConfig(NioServerSocketChannel channel, ServerSocket javaSocket) { super(channel, javaSocket); } @Override protected void autoReadCleared() { clearReadPending(); } @Override public <T> boolean setOption(ChannelOption<T> option, T value) { if (PlatformDependent.javaVersion() >= 7 && option instanceof NioChannelOption) { return NioChannelOption.setOption(jdkChannel(), (NioChannelOption<T>) option, value); } return super.setOption(option, value); } @Override public <T> T getOption(ChannelOption<T> option) { if (PlatformDependent.javaVersion() >= 7 && option instanceof NioChannelOption) { return NioChannelOption.getOption(jdkChannel(), (NioChannelOption<T>) option); } return super.getOption(option); } @SuppressWarnings("unchecked") @Override public Map<ChannelOption<?>, Object> getOptions() { if (PlatformDependent.javaVersion() >= 7) { return getOptions(super.getOptions(), NioChannelOption.getOptions(jdkChannel())); } return super.getOptions(); } private ServerSocketChannel jdkChannel() { return ((NioServerSocketChannel) channel).javaChannel(); } }
NioServerSocketChannel的初始化
-
ServerBootstrap
的init(Channel channel)
方法- 设置自定义的
ChannelOption
和AttributeKey
- 设置自定义的
ChildChannelOption
和ChildAttributeKey
- 设置
ChannelPipeline
- 添加
ServerBootstrapAcceptor
@Override void init(Channel channel) throws Exception { final Map<ChannelOption<?>, Object> options = options0(); synchronized (options) { setChannelOptions(channel, options, logger); } final Map<AttributeKey<?>, Object> attrs = attrs0(); synchronized (attrs) { for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) { @SuppressWarnings("unchecked") AttributeKey<Object> key = (AttributeKey<Object>) e.getKey(); channel.attr(key).set(e.getValue()); } } ChannelPipeline p = channel.pipeline(); final EventLoopGroup currentChildGroup = childGroup; final ChannelHandler currentChildHandler = childHandler; final Entry<ChannelOption<?>, Object>[] currentChildOptions; final Entry<AttributeKey<?>, Object>[] currentChildAttrs; synchronized (childOptions) { currentChildOptions = childOptions.entrySet().toArray(newOptionArray(0)); } synchronized (childAttrs) { currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0)); } p.addLast(new ChannelInitializer<Channel>() { @Override public void initChannel(final Channel ch) throws Exception { final ChannelPipeline pipeline = ch.pipeline(); ChannelHandler handler = config.handler(); if (handler != null) { pipeline.addLast(handler); } ch.eventLoop().execute(new Runnable() { @Override public void run() { pipeline.addLast(new ServerBootstrapAcceptor( ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs)); } }); } }); }
- 设置自定义的
AbstractChannel.doRegister
-
注册Channel
@Override protected void doRegister() throws Exception { boolean selected = false; for (;;) { try { //jdk中SelectableChannel类的 register(Selector sel, int ops, Object attachment),使用一个给定的Selector注册Channel。事件是0表示不关心任何事件(这里仅仅是将Channel绑定到Selector上)。 this表示attachment,即Netty的AbstractNioChannel,当Selector轮询到当前javaChannel()上时,可以通过attachment获取Netty的AbstractNioChannel。这是一个很巧妙的设计 selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this); return; } catch (CancelledKeyException e) { //当试图使用不再SelectionKey时,抛出此异常。 if (!selected) { //`SelectionKey`代表Channel与Selector的注册关系,可以调用`cancel()`取消这种关系,但是这种注销关系并不是立即生效,因为尚未调用Select.select(),所以一旦发现此异常,需要调用selectNow()让这种取消关系生效。 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; } } } }
AbstractChannel.bind
-
端口绑定
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) { assertEventLoop(); if (!promise.setUncancellable() || !ensureOpen(promise)) { return; } // See: https://github.com/netty/netty/issues/576 if (Boolean.TRUE.equals(config().getOption(ChannelOption.SO_BROADCAST)) && localAddress instanceof InetSocketAddress && !((InetSocketAddress) localAddress).getAddress().isAnyLocalAddress() && !PlatformDependent.isWindows() && !PlatformDependent.maybeSuperUser()) { // Warn a user about the fact that a non-root user can't receive a // broadcast packet on *nix if the socket is bound on non-wildcard address. logger.warn( "A non-root user can't receive a broadcast packet if the socket " + "is not bound to a wildcard address; binding to a non-wildcard " + "address (" + localAddress + ") anyway as requested."); } //Channel是否激活 @1 boolean wasActive = isActive(); try { // 调用JDK底层的bind @2 doBind(localAddress); } catch (Throwable t) { safeSetFailure(promise, t); closeIfClosed(); return; } //端口绑定完成会返回true @3 if (!wasActive && isActive()) { invokeLater(new Runnable() { @Override public void run() { //@4 pipeline.fireChannelActive(); } }); } safeSetSuccess(promise); }
@1: 对于NioServerSocketChannel
来说,在服务端启动的时候一定是未激活的(因为端口绑定未完成)
@2:NioServerSocketChannel
的doBind()方法
protected void doBind(SocketAddress localAddress) throws Exception {
if (PlatformDependent.javaVersion() >= 7) {
javaChannel().bind(localAddress, config.getBacklog());
} else {
javaChannel().socket().bind(localAddress, config.getBacklog());
}
}
@3:此时端口绑定已经完成。校验是否是端口绑定完成之前是false,绑定完成之后是true
@4:这里的pipeline
是DefaultChannelPipeline
实例对象,此pipeline的第一个节点是HeadContext
(DefaultChannelPipeline
的构造方法如下)。实际上调用的就是HeadContext
的channelActive()
方法
```java
protected DefaultChannelPipeline(Channel channel) {
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
tail = new TailContext(this);
head = new HeadContext(this);
head.next = tail;
tail.prev = head;
}
```
-
分析
HeadContext
的channelActive@Override public void channelActive(ChannelHandlerContext ctx) throws Exception { ctx.fireChannelActive(); //@1 readIfIsAutoRead(); } //触发一个read事件 @2 private void readIfIsAutoRead() { if (channel.config().isAutoRead()) { channel.read(); } } //调用pipeline的read方法 @3 @Override public Channel read() { pipeline.read(); return this; } //DefaultChannelPipeline的read() @4 @Override public final ChannelPipeline read() { tail.read(); return this; } //AbstractChannelHandlerContext的read() @5 @Override public ChannelHandlerContext read() { final AbstractChannelHandlerContext next = findContextOutbound(); EventExecutor executor = next.executor(); if (executor.inEventLoop()) { next.invokeRead(); } else { Runnable task = next.invokeReadTask; if (task == null) { next.invokeReadTask = task = new Runnable() { @Override public void run() { next.invokeRead(); } }; } executor.execute(task); } return this; } //AbstractChannelHandlerContext的invokeRead() @6 private void invokeRead() { if (invokeHandler()) { try { //调用HeadContext的read(ChannelHandlerContext ctx) ((ChannelOutboundHandler) handler()).read(this); } catch (Throwable t) { notifyHandlerException(t); } } else { read(); } } //DefaultChannelPipeline中HeadContext的read() @7 @Override public void read(ChannelHandlerContext ctx) { unsafe.beginRead(); } //AbstractChannel.AbstractUnsafe类的beginRead @8 @Override public final void beginRead() { assertEventLoop(); if (!isActive()) { return; } try { doBeginRead(); //@9 } catch (final Exception e) { invokeLater(new Runnable() { @Override public void run() { pipeline.fireExceptionCaught(e); } }); close(voidPromise()); } }
调用流程
@1->@2->@3->@4->@5->@6->@7->@8
@9: AbstractNioChannel
的doBeginRead()
方法,this.selectionKey
是服务端注册时返回的selectionKey
@Override
protected void doBeginRead() throws Exception {
// Channel.read() or ChannelHandlerContext.read() was called
final SelectionKey selectionKey = this.selectionKey;
if (!selectionKey.isValid()) {
return;
}
readPending = true;
//获取感兴趣的事件,对于服务端,注册Channel之后,感兴趣的事件是0(即仅仅绑定而已),此处readInterestOp是OP_ACCEPT事件
final int interestOps = selectionKey.interestOps();
if ((interestOps & readInterestOp) == 0) {
selectionKey.interestOps(interestOps | readInterestOp);
}
}