RPC 之 windows上使用thrift

来源:互联网 发布:淘宝上的电器是正品吗 编辑:程序博客网 时间:2024/04/30 19:48

摘要:apache thrift作为著名的跨语言,跨平台的RPC框架已经得到了大量应用,比如Hadoop, Cassandra等。与早期的CORBA, DCOM, 以致传统的WebService如基于XML-RPC的 SOAP协议和基于http的restfull ws相比较,其强大的功能和性能以及开发效率都让人侧目。本文目的在于在windows上使用thrift编译一个RPC的java客户端和服务器来体验其使用。

关键字
: RPC , thrift

1.下载和安装thrift
到 http://apache.fayea.com/thrift/0.9.2/thrift-0.9.2.exe 下载,可直接将下载目录加到Windows环境变量,以便可以随时敲thrift-0.9.2命令。

2.编译tutorial.thrift文件为java 代码:
 到 https://git1-us-west.apache.org/repos/asf?p=thrift.git;a=tree;f=tutorial;hb=HEAD 下载tutorial.thrift和shared.thrift 2个文件 ,  先执行   thrift-0.9.2 -gen java  tutorial\shared.thrift  然后执行  thrift-0.9.2 -gen java  tutorial\tutorial.thrift , 可以发现生成了gen-java目录,
 将生成的java 类 进行编译会报错,放于eclipse工程中会发现很多包缺失,比如org.apache.thrift.* ;
 org.apache.thrift报缺失是因为thrift的java类库需要构建出来。如果我们只下载了thrift-0.9.2.exe 那么是不带thrift-0.9.2.jar这个类库的。
 可以下载thrift的源码 (http://mirrors.hust.edu.cn/apache/thrift/0.9.2/thrift-0.9.2.tar.gz)将其解压,到目录lib\java下执行ant (需要之前安装java和ant,并将ant folder\bin加到环境变量).会生成lib\java\build,其下有thrift-0.9.2.jar

3. 写自己的客户端和服务器程序:
添加CalculatorHandler.java :

import java.util.HashMap;import tutorial.Calculator;import tutorial.InvalidOperation;import tutorial.SharedStruct;import tutorial.Work;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.what = work.op.getValue();                io.why = "Cannot divide by 0";                throw io;            }            val = work.num1 / work.num2;            break;        default:            InvalidOperation io = new InvalidOperation();            io.what = 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()");    }}<strong></strong>
添加client.java :
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 tutorial.Calculator;import tutorial.InvalidOperation;import tutorial.Operation;import tutorial.SharedStruct;import tutorial.Work;public class Client {            static void simple() throws Exception {        TTransport transport =  new TSocket("localhost", 9090);        transport.open();        TProtocol protocol = new  TBinaryProtocol(transport);        Calculator.Client client = new Calculator.Client(protocol);        perform(client);        transport.close();            }        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);        }        SharedStruct log = client.getStruct(1);        System.out.println("Check log: " + log.value);      }    /**     * @param args     * @throws Exception     */    public static void main(String[] args) throws Exception {        simple();    }}
添加server.java :

import org.apache.thrift.server.TServer;import org.apache.thrift.server.TServer.Args;import org.apache.thrift.transport.TServerSocket;import org.apache.thrift.transport.TServerTransport;import org.apache.thrift.server.TSimpleServer;import tutorial.Calculator;public class Server {    static final int port_Simple = 9090;    public static void simple(Calculator.Processor processor) {        try {            // Args arg = null;            TServerTransport serverTransport = new TServerSocket(port_Simple);            TServer server = new TSimpleServer(    new Args(serverTransport).processor(processor));            // Use this for a multithreaded server            // TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor));            System.out.println("Starting the simple server...");            server.serve();        } catch (Exception e) {            e.printStackTrace();        }    }    /**     * @param args     */    public static void main(String[] args) {        CalculatorHandler handler = new CalculatorHandler();        Calculator.Processor processor = new Calculator.Processor(handler);        simple(processor);    }}

---引用jar: libthrift-0.9.2.jar, slf4j-*.jar

4.启动 server,再运行client可以看到客户端输出:

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


总结:
1. thrift缺点:

  1)文档少,初学者要花较长时间来琢磨如何写出第一个基于thrift RPC的C/S程序.
  2)文档bug多,文档描述与实际运行的行为不符。比如根据文档的tutorial/tutorial.thrift来生成Java代码时 并没有生成shared.SharedService类。
  3)windows上的thrift编译器(比如thrift-0.9.2.exe)有bug,对于thrift文件中的include指示符支持不好。

2. thrift优点:

  1)跨平台,跨/多语言的支持非常好。比如一个运行在Windows上的c#客户端完全可以访问一个运行在Linux机器上的用Java实现的服务器端。
    thrift编译器可以根据thrift文件编译出针对当下几乎所有流行语言的代码()。
  2)性能好。 如果服务端代码用c/c++则性能更是杠杠的。
  3)开发效率高,手工代码量小。  thrift编译器所生成的代码基本上拿来即可使用,(需要增加服务端代码来实现自己的业务逻辑,但是协议实现,数据类型实现都已经自动生成)。
  4)兼容性好。如果thrift文件更改,那么之前基于老thrift文件的程序仍能良好运行。
 
参考资料:

1. Apache thrift网站:http://thrift.apache.org/
2. RPC性能比较: http://www.useopen.net/blog/2015/rpc-performance.html
3. 董西城的博客: http://dongxicheng.org/search-engine/thrift-rpc/


0 0
原创粉丝点击