io.netty:netty-all:4.1.33.Final
构造方法
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块)。 当应用程序创建大量连接时,这可能会导致不必要的阻塞。查看issue
public 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();
}
}
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));
}
});
}
});
}
注册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;
}
}
}
}
端口绑定
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);
}
}