Thrift源码系列----5.AbstractNonblockingServer源码

前言

        在有了前几章的源码研究基础上,我们本章开始服务器的源码实现探索,本来打算将五种服务模型的源码都分析一遍,但看完源码后,感觉阻塞型服务实现还是比较简单,大家可以自己看看,这里我们只研究非阻塞型服务器源码,而所有的非阻塞型服务器都继承自AbstractNonblockingServer类,因此理解该类是理解非阻塞型服务实现的关键。

TServer

        由于所有的服务模型都是由父类定义好框架,子类进行不同的实现,所以我们需要先了解AbstractNonblockingServer的父类TServer,TServer源码如下:

public abstract class TServer {
  protected TProcessorFactory processorFactory_;//执行器工厂,在创建服务器的时候,我们需要一个TProcessorFactory的参数,即会赋给该变量,在收到请求时,通过该变量来执行业务逻辑
  protected TServerTransport serverTransport_;//监听端口,接收请求
  protected TTransportFactory inputTransportFactory_;//对transport进行封装获取transport,接收客户端数据时使用
  protected TTransportFactory outputTransportFactory_;//对transport进行封装获取transport,输出服务端处理结果时使用
  protected TProtocolFactory inputProtocolFactory_;//将transport封装为protocol对象,接收客户端数据时使用
  protected TProtocolFactory outputProtocolFactory_;//将transport封装为protocol对象,输出服务端处理结果时使用
  private boolean isServing;//服务是否运行中
  protected TServerEventHandler eventHandler_;//服务器执行业务逻辑前的事件执行器(暂时没用,可忽略)
  protected volatile boolean stopped_ = false;//服务是否已经停止

  protected TServer(AbstractServerArgs args) {
    processorFactory_ = args.processorFactory;
    serverTransport_ = args.serverTransport;
    inputTransportFactory_ = args.inputTransportFactory;
    outputTransportFactory_ = args.outputTransportFactory;
    inputProtocolFactory_ = args.inputProtocolFactory;
    outputProtocolFactory_ = args.outputProtocolFactory;
  }

  public abstract void serve();//启动服务,由子类进行实现
  public void stop() {}//停止服务
  省略所有set get方法
}
//TTransportFactory源码
public class TTransportFactory {
  public TTransport getTransport(TTransport trans) {
    return trans;
  }
}

        源码中列举了所有成员变量和关键方法,如果对Thrift框架从客户端到服务端的请求流程有了解的同学,就会很容易理解各个变量在访问过程中的作用,这里给一幅图帮助大家理解。


这里写图片描述
                                                            图片来源于CSDN


        至次,TServer的源码介绍完毕,TServer中相关Args的静态类这里不多介绍,大多的成员变量与TServer对应,起到传递的作用,没有什么业务逻辑,有兴趣的同学自己看下源码,下一节开始AbstractNonblockingServer源码探索。

AbstractNonblockingServer

概要

        由于AbstractNonblockingServer内部的类多,且逻辑复杂,所以在后面研究源码之前,先向大家介绍一下,该类中有哪些内部类、静态类以及相应作用与联系,有助于后面理解源码。


这里写图片描述


        图中我们只介绍类的作用,具体的AbstractNonblockingServer的方法作用我们在后面的章节详讲。
        1.AbstractNonblockingServer:定义了非阻塞型服务的框架及运作流程。
        2.AbstractNonblockingServerArgs:静态类,为非阻塞型服务提供的Args抽象类。
        3.AbstractSelectThread:内部类,定义了一个抽象的非阻塞型IO操作的线程,具体是使用Java Nio中的Select。
        4.FrameBufferState:私有类,表示FrameBuffer处于何种状态。
        5.FrameBuffer:作为一个内部类,依赖AbstractNonblockingServer中的TransportFactory、ProtocolFactory来进行数据的读取、写入、业务接口调用操作。FrameBuffer会被绑定到一个SelectorKey对象,随着AbstractSelectThread轮循SelectorKey得到读写的执行机会,同时处于不同的状态下会在AbstractSelectThread中注册不同的interests事件,将当前通道在读写事件间相互转换。
        6.AsyncFrameBuffer:内部类,FrameBuffer的异步实现,这里不讨论。

AbstractNonblockingServerArgs

        我们先从简单的Args类开始,源码如下:

public static abstract class AbstractNonblockingServerArgs<T extends AbstractNonblockingServerArgs<T>> extends AbstractServerArgs<T> {
    public long maxReadBufferBytes = Long.MAX_VALUE;

    public AbstractNonblockingServerArgs(TNonblockingServerTransport transport) {
      super(transport);
      //设置父类inputTransportFactory_、outputTransportFactory_对象
      transportFactory(new TFramedTransport.Factory());
    }
  }

        相比其父类多了maxReadBufferBytes属性,用于设置读缓冲区的最大字节数,同时发现构造方法中传入了一个TFramedTransport的Factory,源码如下:

public static class Factory extends TTransportFactory {
    private int maxLength_;

    public Factory() {
      maxLength_ = TFramedTransport.DEFAULT_MAX_LENGTH;
    }

    public Factory(int maxLength) {
      maxLength_ = maxLength;
    }
    @Override
    public TTransport getTransport(TTransport base) {
      return new TFramedTransport(base, maxLength_);
    }
  }

        从传入的Factory源码可知,从inputTransportFactory_、outputTransportFactory_ 获取的Transport对象是一个封装好的TFramedTransport对象,也解答了为何当服务端是非阻塞模式时,客户端必须使用TFramedTransport的原因,因为非阻塞服务端会将Transport对象封装为TFramedTransport,关于TFramedTransport,大家只需要知道,TFramedTransport保证先只读四个字段,因为前四个字节代表这次请求或回应的数据量大小,从而让服务端、客户端知道该接收多少字节数的数据代表接收完毕(Java Nio中使用ByteBuffer来保存数据,需要预先设定好ByteBuffer的大小才能保证请求数据读取完整,所以用前四节代表数据字节数大小,预先设定ByteBuffer的size)。

AbstractNonblockingServer

        AbstractNonblockingServer源码及备注如下:

public abstract class AbstractNonblockingServer extends TServer {
  protected final Logger LOGGER = LoggerFactory.getLogger(getClass().getName());

  final long MAX_READ_BUFFER_BYTES;//对应AbstractNonblockingServerArgs中的maxReadBufferBytes
  final AtomicLong readBufferBytesAllocated = new AtomicLong(0);//已分配的读缓存的字节数

  public AbstractNonblockingServer(AbstractNonblockingServerArgs args) {
    super(args);
    MAX_READ_BUFFER_BYTES = args.maxReadBufferBytes;
  }
  //启动服务
  public void serve() {
    //启动IO线程
    if (!startThreads()) {
      return;
    }
    //开始监听端口,接收客户端请求
    if (!startListening()) {
      return;
    }
    //修改服务状态为正在服务中
    setServing(true);
    //启动服务后的阻塞方法,服务停止后通过
    waitForShutdown();
    //修改服务状态为结束服务
    setServing(false);
    //停止监听端口
    stopListening();
  }
  //启动IO线程,子类实现
  protected abstract boolean startThreads();
  //启动服务后的阻塞方法,服务停止后通过,子类实现
  protected abstract void waitForShutdown();
  //开始监听端口,原理和ServerSocket一样,不再详述listen()方法
  protected boolean startListening() {
    try {
      serverTransport_.listen();
      return true;
    } catch (TTransportException ttx) {
      LOGGER.error("Failed to start listening on server socket!", ttx);
      return false;
    }
  }
  //停止监听,同上
  protected void stopListening() {
    serverTransport_.close();
  }
  //对frameBuffer执行业务逻辑,子类实现,后面讲解
  protected abstract boolean requestInvoke(FrameBuffer frameBuffer);
}

        上述源码确定了所有非阻塞类型服务的服务框架,而startThreads()、waitForShutdown()、requestInvoke(FrameBuffer frameBuffer)的实现便显得十分重要,它们会决定服务的效率,整个流程还是容易理解的,下面来看里面用到的其他类。

FrameBuffer

        FrameBuffer是非阻塞服务中真正通过调用Protocol接口实现数据的读写操作的类,与selectionKey进行绑定,会在Selector线程轮循时,让FrameBuffer对象获取到读写的机会。同时是AbstractNonblockingServer的内部类(非静态),由于该类存在多种状态,并根据不同状态表现不同的行为,这里我们介绍下它的所有状态:

private enum FrameBufferState {
    //处于读取 FrameSize的状态,即正在读取本次数据大小值的,读完后进入下一状态
    READING_FRAME_SIZE,
    //正在读真正数据,读完真正数据进入下一状态
    READING_FRAME,
    //数据读取完毕,可调用业务处理方法,业务调用结束后进入下一状态
    READ_FRAME_COMPLETE,
    //业务调用结束,等待被注册为写事件,注册完后进入下一状态
    AWAITING_REGISTER_WRITE,
    //开始向客户端输出结果,输出完后进入下一状态
    WRITING,
    //结果处理完毕,再次等待注册为可读事件,注册成功后回到READING_FRAME_SIZE状态
    AWAITING_REGISTER_READ,
    //前面几个状态出现问题,或者其他情况下,需要关闭该连接时处于该状态,selector轮循时关闭该连接
    AWAITING_CLOSE
  }

        这里我画了一幅图方便理解:


FrameBuffer不同状态下的行为


        下面先贴上FrameBuffer的源码。

   public class FrameBuffer {
    private final Logger LOGGER = LoggerFactory.getLogger(getClass().getName());
    protected final TNonblockingTransport trans_;//与客户端创建的连接,具体的实现是TNonblockingSocket
    protected final SelectionKey selectionKey_;// 当前对象绑定的SelectionKey对象,通过selector轮循会访问到当前对象
    protected final AbstractSelectThread selectThread_;//当前对象所属的 selectThread 线程(用于读写IO操作的线程)
    protected FrameBufferState state_ = FrameBufferState.READING_FRAME_SIZE;//当前对象所处的状态,上面已介绍过
    protected ByteBuffer buffer_;//Java Nio中的buffer对象,trans_进行读写时使用
    protected final TByteArrayOutputStream response_;//执行完业务逻辑后,保存在本地的结果,responseReady()中会将这里面的数据复制到buffer_
    protected final TMemoryInputTransport frameTrans_;//invoke()方法执行时,会将buffer_中的数据复制到此变量
    //下面的四个变量的意义顾名思议,不再多讲,具体的依赖关系查看下面构造方法
    protected final TTransport inTrans_;
    protected final TTransport outTrans_;
    protected final TProtocol inProt_;
    protected final TProtocol outProt_;

    protected final ServerContext context_;//暂不关心,可理解为在业务逻辑调用前,可能需要调用的执行

    public FrameBuffer(final TNonblockingTransport trans,
        final SelectionKey selectionKey,
        final AbstractSelectThread selectThread) {
      trans_ = trans;
      selectionKey_ = selectionKey;
      selectThread_ = selectThread;
      buffer_ = ByteBuffer.allocate(4);//Java Nio相关,第一次读数据的大小FrameSize,所以分配4字节,与TFramedTransport源码对应

      frameTrans_ = new TMemoryInputTransport();//客户端的请求数据 会缓存在该变量中
      response_ = new TByteArrayOutputStream();//不用了解该类,知道保存返回结果即可
      inTrans_ = inputTransportFactory_.getTransport(frameTrans_);//这里实际调用时会返回一个TFramedTransport对象,原因在上面AbstractNonblockingServerArgs源码讲解中,FrameBuffer是AbstractNonblockingServer的内部类,所以能访问外部对象,而AbstractNonblockingServer的inputTransportFactory_、outputProtocolFactory_对象是由AbstractNonblockingServerArgs的参数确定
      outTrans_ = outputTransportFactory_.getTransport(new TIOStreamTransport(response_));//同上
      inProt_ = inputProtocolFactory_.getProtocol(inTrans_);//将transport封装为protocol
      outProt_ = outputProtocolFactory_.getProtocol(outTrans_);//将transport封装为protocol
      //所以其实 inProt_和outProt_最终的引用是frameTrans_、response_。

      if (eventHandler_ != null) {
        context_ = eventHandler_.createContext(inProt_, outProt_);
      } else {
        context_  = null;
      }
    }

    //给当前FrameBuffer一个机会去读,不管读多读少,只要正确读到数据就返回true(即使没读完下次还会继续),读取失败或者参数异常等返回false,返回false即当前FrameBuffer会被清除掉
    1.如果处于READING_FRAME_SIZE状态,则一直到FrameSize读取成功,并通过校验,通过校验后分配buffer,并修改状态到READING_FRAME状态,下次调用该方法时进入方法2
    2.如果处于READING_FRAME状态,则一直到整个Frame读完,注销掉当前的读事件,并修改READ_FRAME_COMPLETE状态
    public boolean read() {
      //处于读 FrameSize状态,需要先读到数据量的大小
      if (state_ == FrameBufferState.READING_FRAME_SIZE) {
        // 该方法下面贴出,作用是从trans_往buffer_中读取一次数据,读
        if (!internalRead()) {
          return false;
        }

        //==0代表buffer_已经读完了FrameSize
        if (buffer_.remaining() == 0) {
          int frameSize = buffer_.getInt(0);
          //下面三个if是对frameSize合法性的判断
          if (frameSize <= 0) {
            LOGGER.error("Read an invalid frame size of " + frameSize
                + ". Are you using TFramedTransport on the client side?");
            return false;
          }
          if (frameSize > MAX_READ_BUFFER_BYTES) {//还记得在AbstractNonblockingServer中的MAX_READ_BUFFER_BYTES么
            LOGGER.error("Read a frame size of " + frameSize
                + ", which is bigger than the maximum allowable buffer size for ALL connections.");
            return false;
          }
          //如果已经超出可分配的字节数,返回true,等待下次是否有释放掉的字节。
          //还记得AbstractNonblockingServer中的readBufferBytesAllocated么
          if (readBufferBytesAllocated.get() + frameSize > MAX_READ_BUFFER_BYTES) {
            return true;
          }

          //通过校验后,已分配字节数自增
          readBufferBytesAllocated.addAndGet(frameSize + 4);

          //分配空间,并将数据大小放进去
          buffer_ = ByteBuffer.allocate(frameSize + 4);
          buffer_.putInt(frameSize);
      //修改状态到 正在读取数据中
          state_ = FrameBufferState.READING_FRAME;
        } else {
          //还没有将FrameSize读完时,返回true,下次继续读,直到读完才走到上面的逻辑
          return true;
        }
      }

      //FrameSize读完,处于正在读数据中
      if (state_ == FrameBufferState.READING_FRAME) {
        if (!internalRead()) {//读一次
          return false;
        }
        //正体数据,Frame也读完了
        if (buffer_.remaining() == 0) {
          selectionKey_.interestOps(0);//注销掉当前BufferFrame的read事件
          state_ = FrameBufferState.READ_FRAME_COMPLETE;//修改为读完数据可执行状态
        }
        return true;
      }
      //走到这一步说明当前state是不对的,返回错误
      LOGGER.error("Read was called but state is invalid (" + state_ + ")");
      return false;
    }

    //尝试写一次
    public boolean write() {
      //处于正在写的状态
      if (state_ == FrameBufferState.WRITING) {
        try {
          //尝试将buffer_中的结果返回给客户端
          if (trans_.write(buffer_) < 0) {
            return false;
          }
        } catch (IOException e) {
          LOGGER.warn("Got an IOException during write!", e);
          return false;
        }

        //==0表示已经写完,
        if (buffer_.remaining() == 0) {
          prepareRead();//准备切换回读模式
        }
        return true;
      }
      //到达这一步表示状态异常,直接返回false
      LOGGER.error("Write was called, but state is invalid (" + state_ + ")");
      return false;
    }
    //修改当前FrameBuffer绑定的selectionKey_在selector中的事件注册类型,只有涉及到 selector事件时才调用该方法,基本为FrameBuffer读完、写完、异常情况
    public void changeSelectInterests() {
      if (state_ == FrameBufferState.AWAITING_REGISTER_WRITE) {
        //当FrameBuffer处于AWAITING_REGISTER_WRITE状态时,注册写事件到selector中,并将当前状态改为WRITING状态
        selectionKey_.interestOps(SelectionKey.OP_WRITE);
        state_ = FrameBufferState.WRITING;
      } else if (state_ == FrameBufferState.AWAITING_REGISTER_READ) {
        //如果是AWAITING_REGISTER_READ状态,则调用prepareRead()方法,准备下一次读取
        prepareRead();
      } else if (state_ == FrameBufferState.AWAITING_CLOSE) {
        //如果处于AWAITING_CLOSE状态,说明当前FrameBuffer有异常,可能是网络、或者客户端断开连接等等造成,调用close方法关闭当前FrameBuffer,并取消selectionKey_
        close();
        selectionKey_.cancel();
      } else {
        //状态异常,打印日志
        LOGGER.error("changeSelectInterest was called, but state is invalid (" + state_ + ")");
      }
    }

    //关闭当前FrameBuffer
    public void close() {
      // if we're being closed due to an error, we might have allocated a
      // buffer that we need to subtract for our memory accounting.
      if (state_ == FrameBufferState.READING_FRAME || 
          state_ == FrameBufferState.READ_FRAME_COMPLETE ||
          state_ == FrameBufferState.AWAITING_CLOSE) {
        readBufferBytesAllocated.addAndGet(-buffer_.array().length);
      }
      trans_.close();
      //不用关心
      if (eventHandler_ != null) {
        eventHandler_.deleteContext(context_, inProt_, outProt_);
      }
    }

    //查看Frame是否读完
    public boolean isFrameFullyRead() {
      return state_ == FrameBufferState.READ_FRAME_COMPLETE;
    }

    //准备返回结果,在业务逻辑处理完后调用
    public void responseReady() {
      //读缓存已经使用完毕,进行释放
      readBufferBytesAllocated.addAndGet(-buffer_.array().length);

      if (response_.len() == 0) {
        //不需要返回,则直接改为AWAITING_REGISTER_READ状态,准备下次读取
        state_ = FrameBufferState.AWAITING_REGISTER_READ;
        buffer_ = null;
      } else {
        //将结果放入到buffer_中
        buffer_ = ByteBuffer.wrap(response_.get(), 0, response_.len());
        //进入等待注册写 模式
        state_ = FrameBufferState.AWAITING_REGISTER_WRITE;
      }
      //注册selector事件变化
      requestSelectInterestChange();
    }

    //FrameBuffer 执行业务 逻辑的地方
    public void invoke() {
      frameTrans_.reset(buffer_.array());//将buffer_的请求数据复制到frameTrans_本地内存中
      response_.reset();//置空response_

      try {
        if (eventHandler_ != null) {//忽略
          eventHandler_.processContext(context_, inTrans_, outTrans_);
        }
        //执行业务逻辑
        processorFactory_.getProcessor(inTrans_).process(inProt_, outProt_);
        responseReady();//准备返回结果
        return;
      } catch (TException te) {
        LOGGER.warn("Exception while invoking!", te);
      } catch (Throwable t) {
        LOGGER.error("Unexpected throwable while invoking!", t);
      }
      //到达这里说明执行有异常,进入等待关闭状态,并注册事件
      state_ = FrameBufferState.AWAITING_CLOSE; 
      requestSelectInterestChange();
    }

    //从trans_往缓存buffer_中读取一次数据
    private boolean internalRead() {
      try {
        if (trans_.read(buffer_) < 0) {
          return false;
        }
        return true;
      } catch (IOException e) {
        LOGGER.warn("Got an IOException in internalRead!", e);
        return false;
      }
    }

    //准备读方法,
    private void prepareRead() {
      //在selector注册读事件
      selectionKey_.interestOps(SelectionKey.OP_READ);
      //为下一次读取进行变量初始化,同构造方法对应
      buffer_ = ByteBuffer.allocate(4);
      state_ = FrameBufferState.READING_FRAME_SIZE; //回到最初状态
    }
     //请求修改注册事件类型,如果是所属的selectThread执行,直接调用方法即可,非当前线程执行需要将当前FrameBuffer的interests事件注册到当前所属SelectThread中
    protected void requestSelectInterestChange() {
      if (Thread.currentThread() == this.selectThread_) {
        changeSelectInterests();
      } else {
        this.selectThread_.requestSelectInterestChange(this);
      }
    }
  }

        由于源码篇幅过长,这里总结下FrameBuffer主要方法的作用:
        1.read():给FrameBuffer一次机会读数据,读多少不能保证。
        2.write():给FrameBuffer一次机会写数据,写多少不能保证。
        3.changeSelectInterests():修改当前FrameBuffer绑定的SelectorKey在AbstractSelectThread注册的事件类型,一般是读、写、关闭三种事件需要转换时调用。
        4.close():关闭当前连接,释放相应资源。
        5.isFrameFullyRead():当前FrameBuffer是否已将客户端的请求数据读取完成。
        6.responseReady():业务执行完,在返回结果前做准备工作,将结果拷贝到buffer_中。
        7.invoke():从buffer_拷贝数据到frameTrans_,然后执行业务逻辑,最后准备返回结果。
        8.prepareRead():准备回到最初始的 读FrameSize状态。
        9.requestSelectInterestChange():请求将当前FrameBuffer发生的interests事件变化执行或注册到AbstractSelectThread中。

补充:

AbstractSelectThread

        顾名思义,用于Selector非阻塞IO读写的线程,直接贴源码。

protected abstract class AbstractSelectThread extends Thread {
    protected final Selector selector;//NIO的selector,不多讲
    protected final Set<FrameBuffer> selectInterestChanges = new HashSet<FrameBuffer>();//FrameBuffer需要修改已注册到selector的事件时,将把自己放到这个集合,例如业务逻辑处理完后,从读事件到写事件的转换,即会在这里注册

    public AbstractSelectThread() throws IOException {
      this.selector = SelectorProvider.provider().openSelector();
    }
    //唤醒selector
    public void wakeupSelector() {
      selector.wakeup();
    }

    //将FrameBuffer添加到selector interest变化集合中,如果selector阻塞,则唤醒
    public void requestSelectInterestChange(FrameBuffer frameBuffer) {
      synchronized (selectInterestChanges) {
        selectInterestChanges.add(frameBuffer);
      }
      selector.wakeup();
    }

    //检查是否有FrameBuffer需要修改他们的interest 
    protected void processInterestChanges() {
      synchronized (selectInterestChanges) {
        for (FrameBuffer fb : selectInterestChanges) {
          fb.changeSelectInterests();
        }
        selectInterestChanges.clear();//清空事件集合
      }
    }
    //从客户端读取数据,如果已经读完,则执行业务处理
    protected void handleRead(SelectionKey key) {
      FrameBuffer buffer = (FrameBuffer) key.attachment();
      if (!buffer.read()) {
        cleanupSelectionKey(key);//读取失败清除当前连接
        return;
      }
      //如果请求数据读取完毕,执行业务逻辑,执行失败取消连接
      if (buffer.isFrameFullyRead()) {
        if (!requestInvoke(buffer)) {
          cleanupSelectionKey(key);
        }
      }
    }

    //如果有返回结果,向客户端返回数据
    protected void handleWrite(SelectionKey key) {
      FrameBuffer buffer = (FrameBuffer) key.attachment();
      if (!buffer.write()) {
        cleanupSelectionKey(key);
      }
    }
    //连接关闭时的一些清理工作
    protected void cleanupSelectionKey(SelectionKey key) {
      FrameBuffer buffer = (FrameBuffer) key.attachment();
      if (buffer != null) {
        buffer.close();//关闭Socket
      }
      //注销key
      key.cancel();
    }
  }

        总结AbstractSelectThread的方法如下:
        1.wakeupSelector():唤醒selector。
        2.requestSelectInterestChange(FrameBuffer frameBuffer):添加frameBuffer到select事件集合。
        3.processInterestChanges():执行select事件集合的中注册的事件。
        4.handleRead(SelectionKey key):尝试对key进行一次读操作。
        5.handleWrite(SelectionKey key):尝试对key进行一次写操作。
        6.cleanupSelectionKey(SelectionKey key):关闭key连接并做相关清理工作。

调用流程

        至次,AbstractNonblockingServer中所有源码已经讲完,但还是比较难理解的,下面贴一张图来梳理AbstractSelectThread、FrameBuffer、AbstractNonblockingServer间的关系,理解了这三者的关系对于理解非阻塞型的服务模型非常关键。


这里写图片描述

        其中AbstractSelectThread中handleRead(SelectionKey key),processInterestChanges(),handleWrite(SelectionKey key)是子类调用的方法入口,我们按照 一次请求的流程来介绍整个过程。
        1.1.子类调用handRead(SelectionKey key)方法时,会对传入的SelectionKey绑定的FrameBuffer调用read()方法,这里read()可能一次不会读完,有可能多次handRead方法调用才会读完数据,最终读完数据状态转为READ_FRAME_COMPLETE,从而isFrameFullyRead()才会通过。
        1.2.读完数据后,会调用用子类的requestInvoke(buffer)方法,内部最终回调FrameBuffer.invoke()方法,进行业务逻辑处理。
        1.3.业务调用结束后,调整FrameBuffer进入AWAITING_REGISTER_WRITE或AWAITING_REGISTER_READ状态,然后将变更Selector事件类型,这里的requestSelectInterestChange()方法会有判断当前线程是否为所属Select线程,是因为非阻塞服务模型中有单线程、多线程,一般来说,多线程由于业务逻辑的执行是线程池在调用,所以肯定是调用AbstractSelectThread.requestSelectInterestChange(FrameBuffer frameBuffer)将事件变更注册到AbstractSelectThread的事件集合中。
        2.processInterestChanges()由子类调用后,会对事件集合中的FrameBuffer进行已注册的事件转换。
        3.handleWrite(SelectionKey key)由子类调用后,会对传入的SelectionKey绑定的FrameBuffer调用write()方法,同read()一样,可能需要多次才能写完,写完后又回到READING_FRAME_SIZE状态。
        注意:handleRead,handleWrite调用时,如果读写操作出错,则调用cleanupSelectionKey(SelectionKey key)清理key和释放FrameBuffer相关资源。

总结

        这一章讲解了非阻塞型服务器的父类AbstractNonblockingServer中的源码,重点希望读者能理解AbstractSelectThread、FrameBuffer、AbstractNonblockingServer三者间的关系,TNonblockingServer、THsHaServer实现过于简单,后面不做介绍,下章我们直接探索TThreadedSelectorServer的源码实现。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值