Thrift RPC基础学习总结


声明:本文转载自https://my.oschina.net/ososchina/blog/1593051,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

一.什么是Thrift?

Thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++、Java、Python、PHP、Ruby、Erlang、Perl、Haskell、C#、Cocoa、JavaScript、Node.js、Smalltalk、and OCaml 等等编程语言间无缝结合的、高效的服务。

Thrift最初由facebook开发,07年四月开放源码,08年5月进入Apache孵化器。Thrift允许你定义一个简单的定义文件中的数据类型和服务接口。以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。

官网地址:thrift.apache.org

二、Thrift的基础

基本类型:

bool:布尔值,true 或 false,对应 Java 的 boolean byte:8 位有符号整数,对应 Java 的 byte i16:16 位有符号整数,对应 Java 的 short i32:32 位有符号整数,对应 Java 的 int i64:64 位有符号整数,对应 Java 的 long double:64 位浮点数,对应 Java 的 double string:utf-8编码的字符串,对应 Java 的 String

结构体类型:

struct:定义公共的对象,类似于 C 语言中的结构体定义,在 Java 中是一个 JavaBean

容器类型:

list:对应 Java 的 ArrayList set:对应 Java 的 HashSet map:对应 Java 的 HashMap

异常类型:

exception:对应 Java 的 Exception

服务类型:

service:对应服务的类
 

服务端编码基本步骤

  • 实现服务处理接口impl
  • 创建TProcessor
  • 创建TServerTransport
  • 创建TProtocol
  • 创建TServer
  • 启动Server

客户端编码基本步骤

  • 创建Transport
  • 创建TProtocol
  • 基于TTransport和TProtocol创建Client
  • 调用Client的相应方法

数据传输协议

  • TBinaryProtocol 二进制格式
  • TCompactProtocol 压缩格式
  • TJSONProtocol JSON格式
  • TSimpleJSONProtocol 提供JSON只写协议,生成的文件很容易通过脚本语言解析

提示:客户端和服务端的协议要一致

基本关键字

  • oneway  : 表示客户端调用服务器不关心服务器的返回值,不关心服务器程序是否执行完成
  • void :  和oneway一样没有返回值,但是会确保服务器程序执行完成
  • extends:继承,service之间可以通过extends继承

三、简单示例

3.1基本配置

到官网下载最新版本,截止今日(2016-04-23)最新版本为0.9.3

  • 如果是Maven构建项目的,直接在pom.xml 中添加如下内容:
<dependency>     <groupId>org.apache.thrift</groupId>     <artifactId>libthrift</artifactId>     <version>0.9.3</version> </dependency> <dependency>  <groupId>org.slf4j</groupId>  <artifactId>slf4j-log4j12</artifactId>  <version>1.7.5</version> </dependency>
  • 也可以手动配置jar包,在项目中添加如下jar包即可

 

3.2 下载thrift并且配置环境变量

下载thrift 工具,将thrift-x.x.x.exe修改完thrift.exe,并且将次程序所在位置添加到path环境变量中。

 

3.3 生成简单示例

shared.thrift

 namespace cpp 	com.itest.thrift.shared   #c++中的命名空间 namespace java 	com.itest.thrift.shared   #java 包名 namespace php 	com.itest.thrift.shared   #php命名空间  struct SharedStruct {   1: i32 key   2: string value }  service SharedService {   SharedStruct getStruct(1: i32 key) } 

tutorial.thrift

 include "shared.thrift" #引入shared.thrift  namespace cpp com.itest.thrift.service namespace java com.itest.thrift.service namespace php com.itest.thrift.service  /**  * 定义c风格的数据类型  *   */ typedef i32 MyInteger  /**  * 定义常量  *   */ const i32 INT32CONSTANT = 9853 const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}  /**  *   * 定义枚举  */ enum Operation {  //php默认不支持枚举,但这里也会通过其他方式生成php枚举   ADD = 1,   SUBTRACT = 2,   MULTIPLY = 3,   DIVIDE = 4 }  /**  *   * 定义结构体,在php和java中生成bean,在c++中是结构体  */ struct Work {   1: i32 num1 = 0,   2: i32 num2,   3: Operation op,   4: optional string comment, }  /**  * 定义异常类型,扩展性很强  */ exception InvalidOperation {   1: i32 whatOp,   2: string why }  /**  * 定义服务,这里也可以继承其他服务  */ service Calculator extends shared.SharedService {    /**    * 定义服务方法    */     void ping(),     i32 add(1:i32 num1, 2:i32 num2),     i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),     /**     * 此方法表示客户端只发送请求,不关心程序的执行和执行结果,和void不同,void需要确认程序执行结束     */    oneway void zip()  }  

 

 

3.4生成代码

执行如下命令(更多命令,请执行 thrift --help 查询)

thrift -o ./ -out ./ -r -gen java tutorial.thrift

将生成的代码添加到项目中,如下:


3.4 实现接口Iface

package com.itest.thrift.handler;   import java.util.HashMap;  import com.itest.thrift.service.InvalidOperation; import com.itest.thrift.service.Work; import com.itest.thrift.service.Calculator; import com.itest.thrift.shared.SharedStruct; // Generated code  public class CalculatorHandler implements Calculator.Iface {    private HashMap<Integer,SharedStruct> log;    public CalculatorHandler() {     log = new HashMap<Integer, SharedStruct>();   }    public void ping() {     System.out.println("ping()");   }    public int add(int n1, int n2) {     System.out.println("add(" + n1 + "," + n2 + ")");     return n1 + n2;   }    public int calculate(int logid, Work work) throws InvalidOperation {     System.out.println("calculate(" + logid + ", {" + work.op + "," + work.num1 + "," + work.num2 + "})");     int val = 0;     switch (work.op) {     case ADD:       val = work.num1 + work.num2;       break;     case SUBTRACT:       val = work.num1 - work.num2;       break;     case MULTIPLY:       val = work.num1 * work.num2;       break;     case DIVIDE:       if (work.num2 == 0) {         InvalidOperation io = new InvalidOperation();         io.whatOp = work.op.getValue();         io.why = "Cannot divide by 0";         throw io;       }       val = work.num1 / work.num2;       break;     default:       InvalidOperation io = new InvalidOperation();       io.whatOp = work.op.getValue();       io.why = "Unknown operation";       throw io;     }      SharedStruct entry = new SharedStruct();     entry.key = logid;     entry.value = Integer.toString(val);     log.put(logid, entry);      return val;   }    public SharedStruct getStruct(int key) {     System.out.println("getStruct(" + key + ")");     return log.get(key);   }    public void zip() {     System.out.println("zip()");   }  } 

3.5发布服务

package com.iuap.thirft.itest; 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;  import com.itest.thrift.handler.CalculatorHandler; import com.itest.thrift.service.Calculator; // Generated code  public class JavaServer {    public static CalculatorHandler handler;    @SuppressWarnings("rawtypes")   public static Calculator.Processor processor;    @SuppressWarnings("rawtypes")   public static void main(String [] args) {     try {       handler = new CalculatorHandler();       processor = new Calculator.Processor(handler);        Runnable simple = new Runnable() {         public void run() {           simple(processor);         }       };             new Thread(simple).start();     } catch (Exception x) {       x.printStackTrace();     }   }    public static void simple(@SuppressWarnings("rawtypes") Calculator.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();     }   }  }

3.6调用服务

package com.iuap.thirft.itest; 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;  import com.itest.thrift.service.Calculator; import com.itest.thrift.service.InvalidOperation; import com.itest.thrift.service.Operation; import com.itest.thrift.service.Work; import com.itest.thrift.shared.SharedStruct;  public class JavaClient {   public static void main(String [] args) {       try {       TTransport transport;   //    if (args[0].contains("simple")) {         transport = new TSocket("localhost", 9090);         transport.open();     /*  }       else {         TSSLTransportParameters params = new TSSLTransportParameters();         params.setTrustStore("../../lib/java/test/.truststore", "thrift", "SunX509", "JKS");         transport = TSSLTransportFactory.getClientSocket("localhost", 9091, 0, params);       }*/        TProtocol protocol = new  TBinaryProtocol(transport);       Calculator.Client client = new Calculator.Client(protocol);        perform(client);        transport.close();     } catch (TException x) {       x.printStackTrace();     }    }    private static void perform(Calculator.Client client) throws TException   {     client.ping();     System.out.println("ping()");      int sum = client.add(1,1);     System.out.println("1+1=" + sum);      Work work = new Work();      work.op = Operation.DIVIDE;     work.num1 = 1;     work.num2 = 0;     try {       int quotient = client.calculate(1, work);       System.out.println("Whoa we can divide by 0");     } catch (InvalidOperation io) {       System.out.println("Invalid operation: " + io.why);     }      work.op = Operation.SUBTRACT;     work.num1 = 15;     work.num2 = 10;     try {       int diff = client.calculate(1, work);       System.out.println("15-10=" + diff);     } catch (InvalidOperation io) {       System.out.println("Invalid operation: " + io.why);     }          client.zip();      SharedStruct log = client.getStruct(1);     System.out.println("Check log: " + log.value);   } }

 

3.7执行结果

服务器端

Starting the simple server... ping() add(1,1) calculate(1, {DIVIDE,1,0}) calculate(1, {SUBTRACT,15,10}) zip() getStruct(1) ping() add(1,1) calculate(1, {DIVIDE,1,0}) calculate(1, {SUBTRACT,15,10}) zip() getStruct(1)

客户端

ping() 1+1=2 Invalid operation: Cannot divide by 0 15-10=5 Check log: 5

 

四、注意事项

①thrift服务调用也可以通过异步方式,需要继承AsyncIface,并且实现TNonblockingServer模型

②命令中的 -gen的值确定生成不同语言的代码,如-gen php,-gen java

③thrift需要各种语言的支持库或者虚拟机才能生成代码,因此需要下载不同的虚拟机SDK,配置相应的环境变量。

 

 

本文发表于2017年12月21日 14:33
(c)注:本文转载自https://my.oschina.net/ososchina/blog/1593051,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 1919 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1