服务端启动的流程
创建服务端channel
AbstractBootstrap.java
private ChannelFuture doBind(final SocketAddress localAddress) {
/**
* initAndRegister():创建服务端的channel
*/
final ChannelFuture regFuture = initAndRegister();
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
/**
* channelFactory根据反射创建channel,channel类型在启动类的.channel中指定
*/
channel = channelFactory.newChannel();
init(channel);
}
在创建服务端channel的时候都做了哪些事情,可以从NioServerSocketchannel的构造函数中观察:
public NioServerSocketChannel() {
/**
* 创建jdk底层的socket
*/
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
public NioServerSocketChannel(ServerSocketChannel channel) {
super(null, channel, SelectionKey.OP_ACCEPT);
/**
* 创建tcp参数配置类,比如backlog reuseaddr ,专属于单独的服务端或者客户端channel
*/
config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}
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) {
logger.warn(
"Failed to close a partially initialized socket.", e2);
}
throw new ChannelException("Failed to enter non-blocking mode.", e);
}
}
protected AbstractChannel(Channel parent) {
this.parent = parent;
id = newId();
unsafe = newUnsafe();
/**
* pipeline客户端逻辑的相关链
*/
pipeline = newChannelPipeline();
}
初始化服务端channel
set ChildOptions与ChildAttrs:为服务端创建的新连接的channel设定的,每一个新建连接都会设置属性
add ServerBootstrapAcceptor:每一个服务端的pipeline都会有一个ServerBootstrapAcceptor这个特殊的处理器,这个特殊的处理器会为每一个新建立的连接分配一个Nio线程。
初始化流程源码分析
@Override
void init(Channel channel) {
setChannelOptions(channel, newOptionsArray(), logger);
setAttributes(channel, newAttributesArray());
ChannelPipeline p = channel.pipeline();
/**
* 设置childgroup,相当于在启动类设置的workerGroup
*/
final EventLoopGroup currentChildGroup = childGroup;
/**
* 为每一个客户端连接接入设置的handler处理逻辑
*/
final ChannelHandler currentChildHandler = childHandler;
/**
* 在启动类设置的childOptions与childAttrs
*/
final Entry<ChannelOption<?>, Object>[] currentChildOptions = newOptionsArray(childOptions);
final Entry<AttributeKey<?>, Object>[] currentChildAttrs = newAttributesArray(childAttrs);
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) {
final ChannelPipeline pipeline = ch.pipeline();
/**
* 添加服务端的handler,服务端也可以自己设置serverbootstrap.handler
*/
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));
}
});
}
});
}
注册selector
服务端channel创建初始化完成之后,然后做的就是注册到事件轮询器当中
@Override
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
/**
* 绑定eventloop(绑定线程),后续对这个channel的读写事件都交由这个线程来做
*/
AbstractChannel.this.eventLoop = eventLoop;
if (eventLoop.inEventLoop()) {
register0(promise);
} else {
try {
eventLoop.execute(new Runnable() {
@Override
public void run() {
实际注册方法
register0(promise);
}
});
} catch (Throwable t) {
logger.warn(
"Force-closing a channel whose registration task was not accepted by an event loop: {}",
AbstractChannel.this, t);
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
}
private void register0(ChannelPromise promise) {
try {
// check if the channel is still open as it could be closed in the mean time when the register
// call was outside of the eventLoop
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
/**
* 调用jdk底层channel进行注册
*/
doRegister();
neverRegistered = false;
registered = true;
// Ensure we call handlerAdded(...) before we actually notify the promise. This is needed as the
// user may already fire events through the pipeline in the ChannelFutureListener.
/**
* 调用回调方法,如果服务端或者客户端的handler重写了channelAdded,则服务端的channelAdded方法会被调用
*/
pipeline.invokeHandlerAddedIfNeeded();
safeSetSuccess(promise);
/**
* 调用回调方法,如果服务端或者客户端的handler重写了channelRegister,则服务端的channelRegister方法会被调用
*/
pipeline.fireChannelRegistered();
// Only fire a channelActive if the channel has never been registered. This prevents firing
// multiple channel actives if the channel is deregistered and re-registered.
if (isActive()) {
if (firstRegistration) {
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
// This channel was registered before and autoRead() is set. This means we need to begin read
// again so that we process inbound data.
//
// See https://github.com/netty/netty/issues/4805
beginRead();
}
}
}
@Override
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
/**
* javachannel():jdk底层的channel
* 可以看到这里做的就是将jdk底层的channel注册到selector上面,同时通过一个
* attachment将服务端的channel绑定到selector,所以如果selector轮询到jdk底层channel
* 有读写事件发生的时候,就可以拿到我们netty的NioServerSocketChannel或者NioSocketChanel
* 针对netty的channel做事件传播
* 0:代表没有注册任何事件
*/
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;
}
}
}
}
端口绑定
@Override
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.");
}
在绑定之前 isActive()返回的是false
boolean wasActive = isActive();
try {
/**
* 调用jdk底层的bind方法进行端口地址绑定
*/
doBind(localAddress);
} catch (Throwable t) {
safeSetFailure(promise, t);
closeIfClosed();
return;
}
/**
* 在没有绑定之前是false,在绑定之后isActive返回就是true了,这时候可以向下传播
* active事件
*/
if (!wasActive && isActive()) {
invokeLater(new Runnable() {
@Override
public void run() {
/**
* 传播active事件
*/
pipeline.fireChannelActive();
}
});
}
safeSetSuccess(promise);
}
在绑定端口之后,会调用pipeline.fireChannelActive(),进行事件传播,事件传播从pipeline的head头结点开始向下传播。在头结点的channelActive中会调用 readIfIsAutoRead();最后会传播到AbstractChannel的AbstractUnsafe的beginread方法,这个beginread方法最终会调用到
AbstractNioChannel的dobeginread方法
@Override
protected void doBeginRead() throws Exception {
// Channel.read() or ChannelHandlerContext.read() was called
回到之前注册jdk底层channel的时候,返回了一个selectionkey,对于服务端channl注册的感兴趣事件为0,
同时在创建服务端channel的时候,见下面代码,保存的readInterestOp为连接事件
final SelectionKey selectionKey = this.selectionKey;
if (!selectionKey.isValid()) {
return;
}
readPending = true;
如果是服务端chnanel返回的是0
final int interestOps = selectionKey.interestOps();
所以下面的代码表示已经绑定成功了,告诉selector要关心一个acceept事件,selector发现如果有新连接
接入就回交由netty来处理
if ((interestOps & readInterestOp) == 0) {
selectionKey.interestOps(interestOps | readInterestOp);
}
}
```java
public NioServerSocketChannel(ServerSocketChannel channel) {
/**
* SelectionKey.OP_ACCEPT:相当于注册感兴趣事件为连接事件
*/
super(null, channel, SelectionKey.OP_ACCEPT); ----》super(parent, ch, readInterestOp);
/**
* 创建tcp参数配置类,比如backlog reuseaddr ,专属于单独的服务端或者客户端channel
*/
config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}
之前服务端底层socketchannel注册的ops为0,代表不监听任何事件,这时候端口绑定的时候调用
readIfIsAutoRead,就是将之前绑定到selector事件重新绑定为accept事件,这样有新连接新来,selector就会轮询到一个accept事件,这时候就可以将这个连接较为netty来处理。
## 监听端口