Thrift框架主要分为四层:Service,Protocol,Transport,Server。前述介绍的TNonBlockingServer就是一种Server,除此之外,还有很多别的Server,比TNonBlockingServer要简单的多,以后会简要介绍其中的一两个。Service由程序员自己编写,是实际的RPC调用体。还剩中间俩:Protocol是对函数调用的名称、参数、返回值的序列化和反序列化协议,最常见的是TBinaryProtocol;Transport是数据传送的方式,比如TFramedTransport,他TCP字节流分为一个个的帧,在帧数据前面加上长度作为帧头部。这两个都非常枯燥,这里用一个例子来说明从Server是如何调用到Service的实现的。

比如程序员在Thrift声明的服务叫XXX,那么程序员需要实现一个XXXHandler的类,并且这个类要继承XXXIf类。同时,Thrift会帮我们生成一个角XXXProcessor的类,构建Server的时候,需要将这个XXXProcessor的实例或者工厂传递构造方法。这个XXXIf会保存在XXXProcessor对象中。XXXProcessor本身没有process方法,但是它继承自TDispatchProcessor类,TConnection的Task调用process方法,实际调用的就是TDispatchProcessor的process。这个process首先通过Protocol协议的readMessageBegin方法,从接收的消息中读取RPC方法调用名,然后调用dispatchCall方法。这个方法是个纯虚方法,因此调用的实际上是XXXProcessor的dispatchCall方法,代码段又回到了XXXProcessor。

执行过程如下:

1. 从processMap_寻找RPC调用实际上调用的哪个函数,比如原来Thrift声明这个服务有方法YYY(非oneway),而且客户端发起RPC调用的就是YYY。那么寻找的结果为XXXProcessor的process_YYY函数并且调用。

2. 如果之前设置了TProcessEventHandler,那么调用getContext获取调用上下文。

3. 声明上下文的销毁:TProcessorContextFreer对象。process_YYY退出时候,TProcessorContextFreer会被析构,此时会调用freeContext方法。

4. 读取参数:readStructBegin --> (Loop:readFieldBegin读取type --> read具体数据 --> readFieldEnd) --> readStructEnd

5. readMessageEnd。结束读取输入。如果之前设置了TProcessEventHandler,在3、4的前后会调用preRead和postRead。

6. 调用XXXIf实例的YYY方法。设置返回值的.__isset.success=true

7. writeMessageBegin

8. 如果发生异常,写入异常,以及调用其他end函数和flush。一般不要在Thrift声明异常。

9. writeMessageBegin

10. 写入返回值:writeStructBegin --> (如果之前标记了.__isset.success,writeFieldBegin --> write具体数据 --> writeFieldEnd) --> writeFieldStop --> writeStructEnd

11. writeMessageEnd

12. getTransport()->writeEnd()

13. getTransport()->flush()

14. 如果之前设置了TProcessEventHandler,那么在9之前和13之后还会调用preWrite和postWrite。

需要注意的是,getContext的ServerContext是在TConnection调用process之前调用getServerContext时候做的。所以如果需要使用ServerContext,还需要设置并实现XoaServerEventHandler。

Server的介绍基本上可以成为一个小体系了,那么接下来一节,我们主要研究Client的逻辑。