accept 剖析

nio 中如下代码,在 netty 中的流程
//1 阻塞直到事件发生
selector.select();

Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
while (iter.hasNext()) {    
    //2 拿到一个事件
    SelectionKey key = iter.next();
    
    //3 如果是 accept 事件
    if (key.isAcceptable()) {
        
        //4 执行 accept
        ServerSocketChannel c = (ServerSocketChannel) key.channel();
		SocketChannel sc = c.accept();
		sc.configureBlocking(false);
        //注册到selector,关注 read 事件
        sc.register(selector, SelectionKey.OP_READ);
        
    }
    // ...
}
netty启动代码:
public class TestSourceServer {
    public static void main(String[] args) {
        new ServerBootstrap()
                .group(new NioEventLoopGroup())
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) {
                        ch.pipeline().addLast(new LoggingHandler());
                    }
                }).bind(8080);
    }
}
public class HelloClient {
    public static void main(String[] args) throws InterruptedException {
        // 1. 启动类
        new Bootstrap()
            // 2. 添加 EventLoop
            .group(new NioEventLoopGroup())
            // 3. 选择客户端 channel 实现
            .channel(NioSocketChannel.class)
            // 4. 添加处理器
            .handler(new ChannelInitializer<NioSocketChannel>() {
                @Override // 在连接建立后被调用
                protected void initChannel(NioSocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new StringEncoder());
                }
            })
            // 5. 连接到服务器
            .connect(new InetSocketAddress("localhost", 8080))
            .sync()
            .channel()
            // 6. 向服务器发送数据
            .writeAndFlush("hello, world");
    }
}
在netty也是如此步骤,接着来分析下在哪些地方执行了这些步骤:
1.先来看可接入事件处理(accept)

关键代码 io.netty.channel.nio.AbstractNioMessageChannel.NioMessageUnsafe#read

public abstract class AbstractNioMessageChannel extends AbstractNioChannel {

  private final class NioMessageUnsafe extends AbstractNioUnsafe {
  
      private final List<Object> readBuf = new ArrayList<Object>();
  
      @Override
      public void read() {
          assert eventLoop().inEventLoop();
          final ChannelConfig config = config();
          final ChannelPipeline pipeline = pipeline();
          final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();
          allocHandle.reset(config);
  
          boolean closed = false;
          Throwable exception = null;
          try {
              try {
                  do {
                      // doReadMessages 中执行了 accept 并创建 NioSocketChannel 作为消息放入 readBuf
                      // readBuf 是一个 ArrayList 用来缓存消息
                      int localRead = doReadMessages(readBuf);
                      if (localRead == 0) {
                          break;
                      }
                      if (localRead < 0) {
                          closed = true;
                          break;
                      }
                      // localRead 为 1,就一条消息,即接收一个客户端连接
                      allocHandle.incMessagesRead(localRead);
                  } while (allocHandle.continueReading());
              } catch (Throwable t) {
                  exception = t;
              }
  
              int size = readBuf.size();
              for (int i = 0; i < size; i ++) {
                  readPending = false;
                  // 触发 read 事件,让 pipeline 上的 handler 处理,这时是处理
                  // io.netty.bootstrap.ServerBootstrap.ServerBootstrapAcceptor#channelRead
                  pipeline.fireChannelRead(readBuf.get(i));
              }
              readBuf.clear();
              allocHandle.readComplete();
              pipeline.fireChannelReadComplete();
  
              if (exception != null) {
                  closed = closeOnReadError(exception);
  
                  pipeline.fireExceptionCaught(exception);
              }
  
              if (closed) {
                  inputShutdown = true;
                  if (isOpen()) {
                      close(voidPromise());
                  }
              }
          } finally {
              // Check if there is a readPending which was not processed yet.
              // This could be for two reasons:
              // * The user called Channel.read() or ChannelHandlerContext.read() in channelRead(...) method
              // * The user called Channel.read() or ChannelHandlerContext.read() in channelReadComplete(...) method
              //
              // See https://github.com/netty/netty/issues/2254
              if (!readPending && !config.isAutoRead()) {
                  removeReadOp();
              }
          }
      }
  }
  
}
public class NioServerSocketChannel extends AbstractNioMessageChannel
                             implements io.netty.channel.socket.ServerSocketChannel {
                             
  @Override
  protected int doReadMessages(List<Object> buf) throws Exception {
      // javaChannel()是ServerSocketChannel
      SocketChannel ch = SocketUtils.accept(javaChannel());
  
      try {
          if (ch != null) {
              // 将SocketChannel和NioServerSocketChannel重新封装放到集合中
              buf.add(new NioSocketChannel(this, ch));
              return 1;
          }
      } catch (Throwable t) {
          logger.warn("Failed to create a new channel from an accepted socket.", t);
  
          try {
              ch.close();
          } catch (Throwable t2) {
              logger.warn("Failed to close a socket.", t2);
          }
      }
  
      return 0;
  }
  
}
public final class SocketUtils {

  public static SocketChannel accept(final ServerSocketChannel serverSocketChannel) throws IOException {
      try {
          return AccessController.doPrivileged(new PrivilegedExceptionAction<SocketChannel>() {
              @Override
              public SocketChannel run() throws IOException {
                  // 通过ServerSocketChannel得到SocketChannel
                  return serverSocketChannel.accept();
              }
          });
      } catch (PrivilegedActionException e) {
          throw (IOException) e.getCause();
      }
  }
  
}
2.执行pipeline.fireChannelRead(readBuf.get(i));

关键代码 io.netty.bootstrap.ServerBootstrap.ServerBootstrapAcceptor#channelRead

public void channelRead(ChannelHandlerContext ctx, Object msg) {
    // 这时的 msg 是 NioSocketChannel
    final Channel child = (Channel) msg;

    // NioSocketChannel 添加  childHandler 即初始化器
    // 也就是Netty启动代码中的匿名内部类的initChannel代码
    child.pipeline().addLast(childHandler);

    // 设置选项
    setChannelOptions(child, childOptions, logger);

    for (Entry<AttributeKey<?>, Object> e: childAttrs) {
        child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
    }

    try {
        // 注册 NioSocketChannel 到 nio worker 线程,接下来的处理也移交至 nio worker 线程
        // 后续就是nio worker 线程来处理任务,并将SocketChannel注册到Selector上,并关注读事件
        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);
    }
}

关键代码:io.netty.channel.AbstractChannel.AbstractUnsafe#register 方法

public final void register(EventLoop eventLoop, final ChannelPromise promise) {
    // 一些检查,略...

    AbstractChannel.this.eventLoop = eventLoop;

    if (eventLoop.inEventLoop()) {
        register0(promise);
    } else {
        try {
            // 这行代码完成的事实是 nio boss -> nio worker 线程的切换
            eventLoop.execute(new Runnable() {
                @Override
                public void run() {
                    register0(promise);
                }
            });
        } catch (Throwable t) {
            // 日志记录...
            closeForcibly();
            closeFuture.setClosed();
            safeSetFailure(promise, t);
        }
    }
}

io.netty.channel.AbstractChannel.AbstractUnsafe#register0

private void register0(ChannelPromise promise) {
    try {
        if (!promise.setUncancellable() || !ensureOpen(promise)) {
            return;
        }
        boolean firstRegistration = neverRegistered;
        doRegister();
        neverRegistered = false;
        registered = true;
		
        // 执行初始化器,执行前 pipeline 中只有 head -> 初始化器 -> tail
        pipeline.invokeHandlerAddedIfNeeded();
        // 执行后就是 head -> logging handler -> my handler -> tail

        safeSetSuccess(promise);
        pipeline.fireChannelRegistered();
        
        if (isActive()) {
            if (firstRegistration) {
                // 触发 pipeline 上 active 事件
                pipeline.fireChannelActive();
            } else if (config().isAutoRead()) {
                beginRead();
            }
        }
    } catch (Throwable t) {
        closeForcibly();
        closeFuture.setClosed();
        safeSetFailure(promise, t);
    }
}

回到了熟悉的代码 io.netty.channel.DefaultChannelPipeline.HeadContext#channelActive

public void channelActive(ChannelHandlerContext ctx) {
    ctx.fireChannelActive();
	// 触发 read (NioSocketChannel 这里 read,只是为了触发 channel 的事件注册,还未涉及数据读取)
    readIfIsAutoRead();
}

io.netty.channel.nio.AbstractNioChannel#doBeginRead

protected void doBeginRead() throws Exception {
    // Channel.read() or ChannelHandlerContext.read() was called
    final SelectionKey selectionKey = this.selectionKey;
    if (!selectionKey.isValid()) {
        return;
    }

    readPending = true;
	// 这时候 interestOps 是 0
    final int interestOps = selectionKey.interestOps();
    if ((interestOps & readInterestOp) == 0) {
        // 关注 read 事件
        selectionKey.interestOps(interestOps | readInterestOp);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值