Thrift使用探秘

Thrift是apache提供的跨语言RPC调用框架,我们通过以下例子说明使用方法

tutorial.thrift:

enum Operation {
  ADD = 1,
  SUBTRACT = 2,
  MULTIPLY = 3,
  DIVIDE = 4
}

struct Work {
  1: i32 num1 = 0,
  2: i32 num2,
  3: Operation op,
  4: optional string comment,
}

service Calculator {
   i32 add(1:i32 num1, 2:i32 num2),
   i32 addList(1:list<Work> workList),
}
通过如下命令:

set inDir=D:/project/build/example
set outDir=D:/project/test

D:/programs/thrift-0.10.0.exe -r --gen java -out %outDir% %inDir%/tutorial.thrift
将生成如下java文件:
Work.java
Operation.java
Calculator.java

public class Client{
    public static void main(String[] args) {
        try {
            TTransport transport = new TSocket("localhost", 9090);

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

            transport.open();

            performs(client);
            
            transport.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void performs(Calculator.Client client){
        Work work1 = new Work();

        work1.op = Operation.DIVIDE;
        work1.num1 = 1;
        work1.num2 = 0;

        Work work2 = new Work();

        work2.op = Operation.SUBTRACT;
        work2.num1 = 15;
        work2.num2 = 10;

        List<Work> workList = new ArrayList<Work>();
        workList.add(work1);
        workList.add(work2);

        int r1 = client.addList(workList);

        System.out.println("addList=" + r1);
        
        int retAdd = client.add(1, 2);
        System.out.println("retAdd=" + retAdd);
    }
}
写一个CalculatorHandler实现Calculator.Iface
public class Server{
    public static void simple(Calculator.Processor processor) {
        try {
            CalculatorHandler handler = new CalculatorHandler();
            Calculator.Processor<CalculatorHandler> processor = new Calculator.Processor<CalculatorHandler>(handler);
            
            TServerTransport serverTransport = new TServerSocket(9090);
            TServer server = new TSimpleServer(new Args(serverTransport).processor(processor));

            server.serve();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

将org.apache.thrift.protocol.TBinaryProtocol中所有read和write方法都加上注释,我们看看运行时的报文结构是怎样的
write是返回报文结构和read一样,所以就不再注释了
--readI32:-2147418111  版本号
--readI32:7            addList的字符长度
--readString:addList
--readI32:1            addList是本次调用的第一个方法
--byte:15              方法addList的第一个元素的类型是TType.LIST
--readI16:1            方法addList的第一个元素的序号
--byte:12              TType.STRUCT,这里指Work
--readI32:2            TType.LIST对象中Work对象的个数
--byte:8               第一个Work对象中第一个元素的类型TType.I32
--readI16:1            第一个Work对象中第一个元素的序号
--readI32:1            第一个Work对象中第一个元素的值
--byte:8               第一个Work对象中第二个元素的类型TType.I32
--readI16:2            第一个Work对象中第二个元素的序号
--readI32:0            第一个Work对象中第二个元素的值
--byte:8               第一个Work对象中第三个元素的类型TType.I32
--readI16:3            第一个Work对象中第三个元素的序号
--readI32:4            第一个Work对象中第三个元素的值Operation.DIVIDE
--byte:0               第一个Work对象结束TType.STOP
--byte:8               第二个Work对象中第一个元素的类型TType.I32
--readI16:1            第二个Work对象中第一个元素的序号
--readI32:15           第二个Work对象中第一个元素的值
--byte:8               第二个Work对象中第二个元素的类型TType.I32
--readI16:2            第二个Work对象中第二个元素的序号
--readI32:10           第二个Work对象中第二个元素的值
--byte:8               第二个Work对象中第三个元素的类型TType.I32
--readI16:3            第二个Work对象中第三个元素的序号
--readI32:2            第二个Work对象中第三个元素的值Operation.SUBTRACT
--byte:0               第二个Work对象结束TType.STOP
--byte:0               方法addList参数结束TType.STOP

--writeI32:-2147418110
--writeI32:7
--writeString:addList
--writeI32:1
--writeByte:8
--writeI16:0
--writeI32:16
--writeByte:0

--readI32:-2147418111  版本号
--readI32:3            add的字符长度
--readString:add
--readI32:2            add是本次调用的第二个方法
--readByte:8           第一个元素的类型是TType.I32
--readI16:1            第一个元素的序号
--readI32:1            第一个元素的值
--readByte:8           第二个元素的类型TType.I32
--readI16:2            第二个元素的序号
--readI32:2            第二个元素的值
--readByte:0           方法add参数结束TType.STOP

--writeI32:-2147418110
--writeI32:3
--writeString:add
--writeI32:2
--writeByte:8
--writeI16:0
--writeI32:3
--writeByte:0
上面的例子只能用于一个接口Calculator,如果还有一个接口Sender该怎么办?
service Sender {
       void ping(),
}
可以使用TMultiplexedProcessor作处理器:
///////////////////////server//////////////////////////
TMultiplexedProcessor processor = new TMultiplexedProcessor();

processor.registerProcessor("Calculator", new Calculator.Processor<CalculatorHandler>(new CalculatorHandler()));
processor.registerProcessor("Sender", new Ping.Processor<SenderHandler>(new SenderHandler()));

TServerTransport t = new TServerSocket(9090);

Args args = new Args(t);
args.processor(processor);

TSimpleServer server =new TSimpleServer(args);
///////////////////////client//////////////////////////
TTransport transport =  new TSocket("localhost", 9090) ;
transport.open();

TProtocol protocol1 = new TMultiplexedProtocol(new TBinaryProtocol(transport), "Calculator");
Calculator.Client client1 = new Calculator.Client(protocol1);

TProtocol protocol2 = new TMultiplexedProtocol(new TBinaryProtocol(transport), "Sender");
Sender.Client client2 = new Sender.Client(protocol2);

上面例子中TProtocol用的是TBinaryProtocol,这种报文虽然是二进制的,但报文还是太大,可以使用TCompactProtocol替换TBinaryProtocol,这样可以将报文压缩

上面例子中TTransport用的是TSocket,这种报文结构没有说明报文长度,无法与netty/mina等第三方IO框架整合,可以使用TFramedTransport,它会在原报文前加上4个字节,并在其中写入其后的报文长度,这样就方便使用了:

TTransport transport = new TFramedTransport(new TSocket("localhost", 9090));




猜你喜欢

转载自blog.csdn.net/netyeaxi/article/details/62234896
今日推荐