thrift

thrift基本概念

thrift_architecture

Thrift通过一个中间语言(IDL, 接口定义语言)来定义RPC的接口和数据类型,然后通过一个编译器生成不同语言的代码(目前支持C++,Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk等),并由生成的代码负责RPC协议层和传输层的实现。我们只需要去实现具体的接口实现就可以了。

数据类型

参见org.apache.thrift.protocol.TType

协议层类型

参见org.apache.thrift.protocol.TProtocol Thrift可以让你选择客户端与服务端之间传输通信协议的类别,在传输协议上总体上划分为文本(text)和二进制(binary)传输协议, 为节约带宽,提供传输效率,一般情况下 使用二进制类型的传输协议为多数,但有时会还是会使用基于文本类型的协议,这需要根据项目/产品中的实际需求:

传输层类型

参见org.apache.thrift.transport.TTransport

服务端类型

参见org.apache.thrift.server.TServer

thrift VS protobuf

Thrift has integrated RPC implementation, while for Protobuf RPC solutions are separated, but available (like Zeroc ICE ). 参照thrift_protobuf

thrift使用

安装

方式一

brew install Boost
brew install libevent
brew install openssl
./configure
sudo make
sudo make install

方式二

brew install thrift

使用

编写a.thrift
namespace java tutorial
namespace py tutorial
typedef i32 int // We can use typedef to get pretty names for the types we are using
service MultiplicationService{
    int multiply(1:int n1, 2:int n2),
}
生成代码
vi hello.thrifht
thrift --gen java a.thrift
接口实现类
import org.apache.thrift.TException;

public class MultiplicationHandler implements MultiplicationService.Iface {

    @Override
    public int multiply(int n1, int n2) throws TException {
        System.out.println("Multiply(" + n1 + "," + n2 + ")");
        return n1 * n2;
    }
}
server
import org.apache.thrift.server.TServer;   
import org.apache.thrift.server.TServer.Args;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;

public class MultiplicationServer {

    public static MultiplicationHandler handler;

    public static MultiplicationService.Processor processor;

    public static void main(String [] args) {
        try {
          handler = new MultiplicationHandler();
          processor = new MultiplicationService.Processor(handler);

          Runnable simple = new Runnable() {
            public void run() {
              simple(processor);
            }
          };     

          new Thread(simple).start();
        } catch (Exception x) {
          x.printStackTrace();
        }
      }

   public static void simple(MultiplicationService.Processor processor) {
       try {
          TServerTransport serverTransport = new TServerSocket(9090);
          TServer server = new TSimpleServer(new Args(serverTransport).processor(processor));

          System.out.println("Starting the simple server...");
          server.serve();
        } catch (Exception e) {
          e.printStackTrace();
        }
   }
}
client
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;

public class MultiplicationClient {
    public static void main(String [] args) {
        try {
          TTransport transport;

          transport = new TSocket("localhost", 9090);
          transport.open();

          TProtocol protocol = new  TBinaryProtocol(transport);
          MultiplicationService.Client client = new MultiplicationService.Client(protocol);

          perform(client);

          transport.close();
        } catch (TException x) {
          x.printStackTrace();
        }
    }

    private static void perform(MultiplicationService.Client client) throws TException{
        int product = client.multiply(3,5);
        System.out.println("3*5=" + product);
    }
}

抓包验证

下边的报文就是上边的例子的,server提供multiply的服务实现,client进行调用。主要看CALL multiply和REPLY multiply

thrift_wireshark

看代码可以看出:我们使用的是传输层我们使用的是TSocket,协议层使用了TBinaryProtocol,服务端我们使用的是TSimpleServer。

似乎还没有官方的协议说明,不过可以从代码里找(各个语言都有实现)

wireshark输出字段与thrift对应表可参照字段说明

thrift中相关类:

org.apache.thrift.protocal.TMessage

org.apache.thrift.protocol.TMessageType: CALL,REPLY,EXCEPTION,ONEWAY

org.apache.thrift.protocol.TField: 域类型,域的id(第几个),域名字

org.apache.thrift.protocol.TType: 参见数据类型

thrift_request

thrift_response

注:不同的协议,报文格式是不同的。

比如将协议由TBinaryProtocol变为TJSONProtocol,发送报文就变成这样了:

thrift_json