Netty 源码解读
新连接接入
我们继续接着上一章深入了解一下,新连接接入的源码。 见io.netty.channel.nio.AbstractNioMessageChannel.NioMessageUnsafe#read
public void read() {
...
try {
try {
do {
//1、读出SocketChannel放入List<Object> readBuf中
int localRead = doReadMessages(readBuf);
...
} while (allocHandle.continueReading());
} catch (Throwable t) {
exception = t;
}
int size = readBuf.size();
for (int i = 0; i < size; i ++) {
readPending = false;
//2、通过pipeline处理SocketChannel
pipeline.fireChannelRead(readBuf.get(i));
}
...
}
1 doReadMessages(readBuf)
见io.netty.channel.socket.nio.NioServerSocketChannel#doReadMessages
@Override
protected int doReadMessages(List<Object> buf) throws Exception {
//这个地方是不是非常熟悉?又是调用底层java nio通过accept创建SocketChannel
SocketChannel ch = javaChannel().accept();
try {
if (ch != null) {
//new 一个netty自己的NioSocketChannel
//对比《从Java NIO到Netty(八)》创建NioServerSocketChannel看
//可以看看有哪些不同点,尤其是成员变量readInterestOp
buf.add(new NioSocketChannel(this, ch));
return 1;
}
} catch (Throwable t) {
...
}
return 0;
}
2 pipeline.fireChannelRead(readBuf.get(i));
这个地方我调过一些中间步骤,建议大家debug跟进不然很难找到。 最终见io.netty.bootstrap.ServerBootstrap.ServerBootstrapAcceptor#channelRead
public void channelRead(ChannelHandlerContext ctx, Object msg) {
...
try {
//复习一下《从Java NIO到Netty(八)》中NioServerSocketChannel是如何注册的
//对比看,这个childGroup就是workerGroup
//就是把我们刚创建的NioSocketChannel注册到这个workerGroup中的一个eventLoop上面去
//我们跟进这里看看
childGroup.register(child).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
forceClose(child, future.cause());
}
}
});
} catch (Throwable t) {
forceClose(child, t);
}
}
childGroup.register(child)的内部源码已经在《从Java NIO到Netty(八)》的1.2注册selector中讲过,大家可以回去再复习一下,现在说一下区别,见io.netty.channel.AbstractChannel.AbstractUnsafe#register0
private void register0(ChannelPromise promise) {
try {
...
//区别在这里,这个isActive()是判断socket是否绑定端口,
//在NioServerSocketChannel注册时,这个地方为false并不会执行,
//但是NioSocketChannel注册时会执行
if (isActive()) {
if (firstRegistration) {
//NioServerSocketChannel是在端口绑定完之后执行fireChannelActive的
//所以会执行这里,跟进这里
pipeline.fireChannelActive();
}
...
}
pipeline.fireChannelActive()的执行逻辑也已经在《从Java NIO到Netty(八)》的1.2.2中讲过,大家可以再回顾一下,区别在于
@Override
protected void doBeginRead() throws Exception {
...
if ((interestOps & readInterestOp) == 0) {
//NioServerSocketChannel把SelectionKey.OP_ACCEPT事件赋值给了这个readInterestOp
//而NioSocketChannel把SelectionKey.OP_READ事件赋值给了这个readInterestOp
selectionKey.interestOps(interestOps | readInterestOp);
}
}
那我们总结一下,新连接接入干了什么事情,是不是和java nio一样?让我们回想一下《从Java NIO到Netty(四)》这块代码
ServerSocketChannel ServerSocketChannel = (ServerSocketChannel)key.channel();
//创建SocketChannel
SocketChannel clientChannel = ServerSocketChannel.accept();
//设置为非阻塞式
clientChannel.configureBlocking(false);
//注册到selector
clientChannel.register(key.selector(), SelectionKey.OP_READ);
是不是如出一辙呢?