系列
Netty源码分析 - Bootstrap服务端
Netty源码分析 - Bootstrap客户端
netty源码分析 - ChannelHandler
netty源码分析 - EventLoop类关系
netty源码分析 - register分析
Netty源码分析 - NioEventLoop事件处理
netty源码分析 - accept过程分析
Netty源码分析 - ByteBuf
Netty源码分析 - 粘包和拆包问题
开篇
- 这篇文章主要用于分析NioSocketChannel注册到NioEventLoop对象的过程,顺带和Nio的例子进行下对比。
- 通过这篇文章能够了解到整个注册过程的脉络为NioEventLoopGroup => NioEventLoop => NioSocketChannel的刘哦吃。
Nio的例子
public class NioEchoServer {
private static final int BUF_SIZE = 256;
private static final int TIMEOUT = 3000;
public static void main(String args[]) throws Exception {
// 打开服务端 Socket,ServerSocketChannel.open()
// 内部执行的是 SelectorProvider.provider().openServerSocketChannel();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// 打开 Selector
Selector selector = Selector.open();
// 服务端 Socket 监听8080端口, 并配置为非阻塞模式
serverSocketChannel.socket().bind(new InetSocketAddress(8080));
serverSocketChannel.configureBlocking(false);
// 将 channel 注册到 selector 中.
// 通常我们都是先注册一个 OP_ACCEPT 事件, 然后在 OP_ACCEPT 到来时, 再将这个 Channel 的 OP_READ
// 注册到 Selector 中.
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
// 通过调用 select 方法, 阻塞地等待 channel I/O 可操作
if (selector.select(TIMEOUT) == 0) {
System.out.print(".");
continue;
}
// 获取 I/O 操作就绪的 SelectionKey, 通过 SelectionKey 可以知道哪些 Channel 的哪类 I/O 操作已经就绪.
Iterator keyIterator = selector.selectedKeys().iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
// 当获取一个 SelectionKey 后, 就要将它删除, 表示我们已经对这个 IO 事件进行了处理.
keyIterator.remove();
if (key.isAcceptable()) {
// 当 OP_ACCEPT 事件到来时, 我们就有从 ServerSocketChannel 中获取一个 SocketChannel,
// 代表客户端的连接
// 注意, 在 OP_ACCEPT 事件中, 从 key.channel() 返回的 Channel 是 ServerSocketChannel.
// 而在 OP_WRITE 和 OP_READ 中, 从 key.channel() 返回的是 SocketChannel.
SocketChannel clientChannel = ((ServerSocketChannel) key.channel()).accept();
clientChannel.configureBlocking(false);
//在 OP_ACCEPT 到来时, 再将这个 Channel 的 OP_READ 注册到 Selector 中.
// 注意, 这里我们如果没有设置 OP_READ 的话, 即 interest set 仍然是 OP_CONNECT 的话, 那么 select 方法会一直直接返回.
clientChannel.register(key.selector(), OP_READ, ByteBuffer.allocate(BUF_SIZE));
}
if (key.isReadable()) {
SocketChannel clientChannel = (SocketChannel) key.channel();
ByteBuffer buf = (ByteBuffer) key.attachment();
long bytesRead = clientChannel.read(buf);
if (bytesRead == -1) {
clientChannel.close();
} else if (bytesRead > 0) {
key.interestOps(OP_READ | SelectionKey.OP_WRITE);
System.out.println("Get data length: " + bytesRead);
}
}
if (key.isValid() && key.isWritable()) {
ByteBuffer buf = (ByteBuffer) key.attachment();
buf.flip();
SocketChannel clientChannel = (SocketChannel) key.channel();
clientChannel.write(buf);
if (!buf.hasRemaining()) {
key.interestOps(OP_READ);
}
buf.compact();
}
}
}
}
}
Netty NioServer
NioServerSocketChannel
- NioServerSocketChannel的类继承关系如上图,核心关注NioServerSocketChannel和AbstraceNioChannel。
- NioServerSocketChannel和AbstraceNioChannel类关注初始化顺序。
public class NioServerSocketChannel extends AbstractNioMessageChannel
implements io.netty.channel.socket.ServerSocketChannel {
private static final ChannelMetadata METADATA = new ChannelMetadata(false, 16);
// SelectorProvider.provider()返回的是单例对象
private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
private final ServerSocketChannelConfig config;
private static ServerSocketChannel newSocket(SelectorProvider provider) {
try {
return provider.openServerSocketChannel();
} catch (IOException e) {
}
}
public NioServerSocketChannel() {
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
public NioServerSocketChannel(ServerSocketChannel channel) {
super(null, channel, SelectionKey.OP_ACCEPT);
config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}
}
public abstract class AbstractNioChannel extends AbstractChannel {
private final SelectableChannel ch;
protected final int readInterestOp;
volatile SelectionKey selectionKey;
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
super(parent);
this.ch = ch;
this.readInterestOp = readInterestOp;
try {
// 如果一个Channel要注册到Selector中, 那么这个Channel必须是非阻塞的
// 即channel.configureBlocking(false);
ch.configureBlocking(false);
} catch (IOException e) {
}
}
protected SelectableChannel javaChannel() {
return ch;
}
}
- NioServerSocketChannel核心关注SelectableChannel和readInterestOp。
- DEFAULT_SELECTOR_PROVIDER是通过SelectorProvider.provider()返回单例对象。
- SelectableChannel对象由provider.openServerSocketChannel()。
- readInterestOp在NioServerSocketChannel中监听事件为SelectionKey.OP_ACCEPT。
- 核心关注ServerSocketChannel,继续关注分析。
- 核心关注SelectorProvider,用于创建ServerSocketChannel对象,继续关注分析。
ServerSocketChannel
- ServerSocketChannel的类关系图如上图所示,突出父类SelectableChannel,解答AbstractNioChannel的参数对象SelectableChannel的缘由。
SelectorProvider
- SelectorProvider的类图如上所示,生成ServerSocketChannel对象,分析下原理。
public abstract class SelectorProvider {
private static final Object lock = new Object();
private static SelectorProvider provider = null;
public static SelectorProvider provider() {
synchronized (lock) {
if (provider != null)
return provider;
return AccessController.doPrivileged(
new PrivilegedAction() {
public SelectorProvider run() {
if (loadProviderFromProperty())
return provider;
if (loadProviderAsService())
return provider;
provider = sun.nio.ch.DefaultSelectorProvider.create();
return provider;
}
});
}
}
}
public abstract class SelectorProviderImpl extends SelectorProvider {
public abstract AbstractSelector openSelector() throws IOException;
public ServerSocketChannel openServerSocketChannel() throws IOException {
return new ServerSocketChannelImpl(this);
}
public SocketChannel openSocketChannel() throws IOException {
return new SocketChannelImpl(this);
}
}
- SelectorProvider#provider用于生成单例的SelectorProvider对象。
- SelectorProviderImpl#openServerSocketChannel负责创建ServerSocketChannel对象。
- SelectorProviderImpl#openSocketChannel负责创建SocketChannel对象。
- 在Netty的体系里面channel对象都是由SelectorProvider来完成的,相当于灵魂。
register分析
- channel注册调用链如上图,按照NioEventLoopGroup => NioEventLoop => NioSocketChannel进行注册。
- 最终的注册是将NioSocketChannel注册到NioEventLoop的selector对象当中。
NioEventLoopGroup注册
public abstract class AbstractBootstrap, C extends Channel> implements Cloneable {
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = channelFactory.newChannel();
init(channel);
} catch (Throwable t) {
}
// 进入NioEventLoopGroup的register过程,进入NioEventLoop的过程
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
return regFuture;
}
}
public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup {
public ChannelFuture register(Channel channel) {
return next().register(channel);
}
}
- config().group().register(channel)的方法中从NioEventLoopGroup执行register方法。
- next().register(channel)的方法实现从NioEventLoopGroup到NioEventLoop的调用传递。
NioEventLoop注册
public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop {
public ChannelFuture register(Channel channel) {
// DefaultChannelPromise(channel, this)的this为NioEventLoop对象
return register(new DefaultChannelPromise(channel, this));
}
public ChannelFuture register(final ChannelPromise promise) {
ObjectUtil.checkNotNull(promise, "promise");
// 由NioEventLoop进入NioSocketChannel的register过程
promise.channel().unsafe().register(this, promise);
return promise;
}
}
- promise.channel().unsafe().register(this, promise)实现由NioEventLoop到NioSocketChannel的调用传递。
NioSocketChannel注册
public abstract class AbstractNioChannel extends AbstractChannel {
protected abstract class AbstractUnsafe implements Unsafe {
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
AbstractChannel.this.eventLoop = eventLoop;
if (eventLoop.inEventLoop()) {
register0(promise);
} else {
try {
eventLoop.execute(new Runnable() {
@Override
public void run() {
register0(promise);
}
});
} catch (Throwable t) {
}
}
}
private void register0(ChannelPromise promise) {
try {
// 省略代码
doRegister();
} catch (Throwable t) {
}
}
}
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
// 绑定NioSocketChannel到NioEventLoop对象当中,并且附加NioSocketChannel对象。
selectionKey = javaChannel().register(eventLoop().selector, 0, this);
return;
} catch (CancelledKeyException e) {
}
}
}
}
- AbstractUnsafe#register执行的NioSocketChannel的注册动作,最终会执行AbstractNioChannel#doRegister。
- AbstractNioChannel#doRegister内部通过javaChannel().register(eventLoop().selector, 0, this)实现绑定Channel到NioEventLoop对象当中。