服务端接受连接,读过程

1. 客户端接收连接:

在这里插入图片描述
在Netty服务端启动的时候,会先启动一个Reactor线程池,去绑定启动的地址和端口,并且线程池中的channel复用器会循环监听客户端的各种事件。实际会调用NioEventLoop中的run方法,代码如下(只保留具体执行代码):

 @Override
 Protected void run(){
     for(;;){
           // Nio 事件监听和执行
          processSelectedKeys();
          // 使用eventLoop执行的任务(使用者加入的)
         runAllTasks();
          }
 

主要看一下 processSelectedKeys()方法,这里包含了服务端对客户端的连接和读取方法。

    
     private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
            final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe(); // 获取channel的unsafe类
            ……(省略代码)
            try {
                int readyOps = k.readyOps();
                // We first need to call finishConnect() before try to trigger a read(...) or write(...) as otherwise
                // the NIO JDK channel implementation may throw a NotYetConnectedException.
                if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
                    // remove OP_CONNECT as otherwise Selector.select(..) will always return without blocking
                    // See https://github.com/netty/netty/issues/924
                    int ops = k.interestOps();
                    ops &= ~SelectionKey.OP_CONNECT;
                    k.interestOps(ops);
    
                    unsafe.finishConnect(); // 连接客户端
                }
    
                // Process OP_WRITE first as we may be able to write some queued buffers and so free memory.
                if ((readyOps & SelectionKey.OP_WRITE) != 0) {
                    // Call forceFlush which will also take care of clear the OP_WRITE once there is nothing left to write
                    ch.unsafe().forceFlush(); // 写操作
                }
    
                // Also check for readOps of 0 to workaround possible JDK bug which may otherwise lead
                // to a spin loop
                if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
                    unsafe.read(); // 读操作或者接受连接操作 || 
                }
            } catch (CancelledKeyException ignored) {
                unsafe.close(unsafe.voidPromise());
            }
        }

当客户端向服务端发起连接,最终调用unsafe类的read方法,因为此时的channel是NioServerSocketChannel.class 实际调用是NioMessageUnsafe.class:

          @Override
         public void read() {
             assert eventLoop().inEventLoop();
             final ChannelConfig config = config(); // DefaultChannelConfig
             final ChannelPipeline pipeline = pipeline(); // DefaultChannelPipeline
             final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle(); // io.netty.channel.AdaptiveRecvByteBufAllocator.HandleImpl
             allocHandle.reset(config);
 
             boolean closed = false;
             Throwable exception = null;
             try {
                 try {
                     do {
                         int localRead = doReadMessages(readBuf); // accept客户端连接,生成ServerSocketChannel 加入readBuf中
                         if (localRead == 0) {
                             break;
                         }
                         if (localRead < 0) {
                             closed = true;
                             break;
                         }
 
                         allocHandle.incMessagesRead(localRead); // 计数
                     } while (allocHandle.continueReading());
                 } catch (Throwable t) {
                     exception = t;
                 }
 
                 int size = readBuf.size();
                 for (int i = 0; i < size; i ++) {
                     readPending = false;
                     pipeline.fireChannelRead(readBuf.get(i)); // 调用channelRead方法,其中将调用ServerBootstrapAcceptor的channelRead方法方法,将ServerSocketChannel注册到childGroup上去。
                 }
                 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();
                 }
             }
         }
     }

可以看到的是,当有客户端发起连接时,服务端这边会调用ServerBootstrapAcceptor中的方法,将客户端连接注册到另一个Reactor线程池中去,这样的话服务端的接受连接和读写操作很好的分开开来,接受连接的线程池可以继续接收客户端连接,而不需要等待此次连接读写完成。

2. 读操作:

与上述代码一致,只是这次使用的时NioSocketChannl,并且Reactor线程池也是不同的,最终也会调用unsafe(NioByteUnsafe)的read方法

      
  @Override
         public final void read() {
             final ChannelConfig config = config();
             if (shouldBreakReadReady(config)) {
                 clearReadPending();
                 return;
             }
             final ChannelPipeline pipeline = pipeline();
             final ByteBufAllocator allocator = config.getAllocator();
             final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle(); 
             allocHandle.reset(config);
 
             ByteBuf byteBuf = null;
             boolean close = false;
             try {
                 do {
                     byteBuf = allocHandle.allocate(allocator); // 默认使用直接内存创建的byteBuf
                     allocHandle.lastBytesRead(doReadBytes(byteBuf));
                     if (allocHandle.lastBytesRead() <= 0) {
                         // nothing was read. release the buffer.
                         byteBuf.release();
                         byteBuf = null;
                         close = allocHandle.lastBytesRead() < 0;
                         if (close) {
                             // There is nothing left to read as we received an EOF.
                             readPending = false;
                         }
                         break;
                     }
 
                     allocHandle.incMessagesRead(1);
                     readPending = false;
                     pipeline.fireChannelRead(byteBuf); // channelHandler责任链中channelRead方法(业务逻辑等等)
                     byteBuf = null;
                 } while (allocHandle.continueReading());
 
                 allocHandle.readComplete();
                 pipeline.fireChannelReadComplete();
 
                 if (close) {
                     closeOnRead(pipeline);
                 }
             } catch (Throwable t) {
                 handleReadException(pipeline, byteBuf, t, close, allocHandle);
             } 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();
                 }
             }
         }
     }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值