• thrift使用总结


    转自 http://blog.csdn.net/qq_27784479/article/details/73250958

    Apache Thrift软件框架用于可扩展的跨语言服务开发,简单来说就是RPC远程调用,它是一个完整的 RPC 框架体系。 
    Thrift支持的数据类型 
    1.基本类型 
    bool:布尔值 (true or false), one byte 
    byte:有符号字节 
    i16:16位有符号整型 
    i32:32位有符号整型 
    i64:64位有符号整型 
    double:64位浮点型 
    string:编码或者二进制的字符串

    2.容器(Containers) 
    Thrift容器与流行编程语言的容器类型相对应,采用Java泛型风格。它有3种可用容器类型: 
    list: 元素类型为t1的有序表,容许元素重复。 
    set:元素类型为t1的无序表,不容许元素重复。 
    map

    namespace java mythrift
    enum HotelType {
       YILONG,
       JINJIANG=2
    } 
    struct Hotel {
      1:  optional i32 id;
      2:  optional string hotelname;
      3:  required HotelType HotelType.YILONG;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    namespace(可省略):命名空间,一方面他可以解决名字冲突的问题,另一方面可以指定生成文件的路径及包名。 
    required、optional:规范的struct定义中的每个域均会使用required或者optional关键字进行标识。如果required标识的域没有赋值,Thrift将给予提示;如果optional标识的域没有赋值,该域将不会被序列化传输。

    引入依赖的thrift文件

    include "***.thrift"
    
    typedef ***.Hotel Hotel
    
    struct Hotels{
        1: optional Hotel hotel;
        2: optional list<string> rooms;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    include:引入thrift文件 * * *为thrit的文件名 
    typedef:定义需要的结构体

    服务类型 
    规则 
    继承类必须实现这些方法 
    参数可以是基本类型或者结构体 
    返回值可以是void 
    服务支持继承,一个service可使用extends关键字继承另一个service 
    服务不支持重载

    namespace java wu.thrift.service
    
    include "result.thrift"
    
    typedef result.TResult TResult
    
    service TResultService{
        TResult getResponse(1:string code);
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    代码实例: 
    两份thrift文件

    namespace java wu.thrift.bean
    struct TResult{
        1: optional string code;
        2: optional string describe;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    namespace java wu.thrift.service
    
    include "result.thrift"
    
    typedef result.TResult TResult
    
    service TResultService{
        TResult getResponse(1:string code);
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    我用的是maven引入的jar 
    我分了两个项目,一个是服务端项目,另一个是客户端项目。

    <dependency>
        <groupId>org.apache.thrift</groupId>
        <artifactId>libthrift</artifactId>
        <version>0.10.0</version>
    </dependency>
    • 1
    • 2
    • 3
    • 4
    • 5

    服务端:

    package wu.thrift.handleService;
    
    import org.apache.thrift.TException;
    
    import wu.thrift.bean.TResult;
    import wu.thrift.service.TResultService;
    
    public class HandleService implements TResultService.Iface{
    
        public TResult getResponse(String code) throws TException {
            TResult result=new TResult();
            result.setCode(code);
            result.setDescribe("成功");
            return result;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    上面的代码是写在服务端项目里的一个业务处理类,它需要实现thrift service类下的一个内部接口类Iface。

    package wu.thrift.server;
    
    import org.apache.thrift.TProcessor;
    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 wu.thrift.handleService.HandleService;
    import wu.thrift.service.TResultService;
    
    public class ThriftServer {
        public static void main(String[] args) {
            try {
                TServerTransport serverTransport = new TServerSocket(9090);
                //定义一个TProcess处理类,创建TProcess对象
                TProcessor processor = new TResultService.Processor<HandleService>(new HandleService());
                //定义一个TServer传输对象,用于tcp的socket通信
                TServer server = new TSimpleServer(new Args(serverTransport).processor(processor));
                System.out.println("Starting the simple server...");
                //启动服务
                server.serve();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    上面的代码是写在服务端项目里的一个服务启动类,里面的一些类的作用可以参考下面server实现描述。

    客户端:

    package wu.thrift.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;
    import org.apache.thrift.transport.TTransportException;
    
    import wu.thrift.bean.TResult;
    import wu.thrift.service.TResultService;
    
    public class ThriftClient {
        public static void main(String[] args) {
            try { 
                   // 创建一个传输层对象(TTransport),设置调用的服务地址为本地,端口为 9090,TSocket传输方式
                   TTransport transport = new TSocket("localhost", 9090);
                   //打开socket,建立与服务器直接的socket连接 
                   transport.open(); 
                   // 创建通信协议对象(TProtocol),设置传输协议为 TBinaryProtocol 
                   TProtocol protocol = new TBinaryProtocol(transport); 
                   //创建一个Thrift客户端对象
                   TResultService.Client client = new TResultService.Client(protocol); 
                   // 调用服务的 getResponse 方法
                   TResult result=client.getResponse("001"); 
                   System.out.println(result.toString());
                   transport.close(); 
               } catch (TTransportException e) { 
                   e.printStackTrace(); 
               } catch (TException e) { 
                   e.printStackTrace(); 
               } 
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    上面的代码是写在客户端项目里的一个服务启动类,里面的一些类的作用同样可以参考下面客户端编写实现描述。

    其实,我为了清晰我选择了分为两个项目(服务端和客户端),其实应该可以分成三个项目,一个服务端项目,一个客户端项目,另外一个thrift实体类项目,然后前面两个项目分别依赖于实体类项目。

    客户端编写 
    传输方式: 
    1. TSocket:阻塞型 socket,用于客户端,采用系统函数 read 和 write 进行读写数据。 
    2. TServerSocket:非阻塞型 socket,用于服务器端,accecpt 到的 socket 类型都是 TSocket(即阻塞型 socket)。 
    3. TBufferedTransport 和 TFramedTransport 都是有缓存的,均继承TBufferBase,调用下一层 TTransport 类进行读写操作吗,结构极为相似。其中 TFramedTransport 以帧为传输单位,帧结构为:4个字节(int32_t)+传输字节串,头4个字节是存储后面字节串的长度,该字节串才是正确需要传输的数据,因此 TFramedTransport 每传一帧要比 TBufferedTransport 和 TSocket 多传4个字节。 
    4. TMemoryBuffer 继承 TBufferBase,用于程序内部通信用,不涉及任何网络I/O,可用于三种模式: 
    (1)OBSERVE模式,不可写数据到缓存; 
    (2)TAKE_OWNERSHIP模式,需负责释放缓存; 
    (3)COPY模式,拷贝外面的内存块到TMemoryBuffer。 
    5. TFileTransport 直接继承 TTransport,用于写数据到文件。对事件的形式写数据,主线程负责将事件入列,写线程将事件入列,并将事件里的数据写入磁盘。这里面用到了两个队列,类型为 TFileTransportBuffer,一个用于主线程写事件,另一个用于写线程读事件,这就避免了线程竞争。在读完队列事件后,就会进行队列交换,由于由两个指针指向这两个队列,交换只要交换指针即可。它还支持以 chunk(块)的形式写数据到文件。 
    6. TFDTransport 是非常简单地写数据到文件和从文件读数据,它的 write 和 read 函数都是直接调用系统函数 write 和 read 进行写和读文件。 
    7. TSimpleFileTransport 直接继承 TFDTransport,没有添加任何成员函数和成员变量,不同的是构造函数的参数和在 TSimpleFileTransport 构造函数里对父类进行了初始化(打开指定文件并将fd传给父类和设置父类的close_policy为CLOSE_ON_DESTROY)。 
    8. TZlibTransport 跟 TBufferedTransport 和 TFramedTransport一样,调用下一层 TTransport 类进行读写操作。它采用提供的 zlib 压缩和解压缩库函数来进行压解缩,写时先压缩再调用底层 TTransport 类发送数据,读时先调用 TTransport 类接收数据再进行解压,最后供上层处理。 
    9. TSSLSocket 继承 TSocket,阻塞型 socket,用于客户端。采用 openssl 的接口进行读写数据。checkHandshake()函数调用 SSL_set_fd 将 fd 和 ssl 绑定在一起,之后就可以通过 ssl 的 SSL_read和SSL_write 接口进行读写网络数据。 
    10. TSSLServerSocket 继承 TServerSocket,非阻塞型 socket, 用于服务器端。accecpt 到的 socket 类型都是 TSSLSocket 类型。 
    11. THttpClient 和 THttpServer 是基于 Http1.1 协议的继承 Transport 类型,均继承 THttpTransport,其中 THttpClient 用于客户端,THttpServer 用于服务器端。两者都调用下一层 TTransport 类进行读写操作,均用到TMemoryBuffer 作为读写缓存,只有调用 flush() 函数才会将真正调用网络 I/O 接口发送数据。

    传输协议: 
    Thrift 传输协议上总体可划分为文本 (text) 和二进制 (binary) 传输协议两大类,一般在生产环境中使用二进制类型的传输协议为多数。 
    TBinaryProtocol:是Thrift的默认协议,使用二进制编码格式进行数据传输,基本上直接发送原始数据 
    TCompactProtocol:压缩的、密集的数据传输协议,基于Variable-length quantity的zigzag 编码格式 
    TJSONProtocol:以JSON (JavaScript Object Notation)数据编码协议进行数据传输 
    TDebugProtocol:常常用以编码人员测试,以文本的形式展现方便阅读

    服务端编写: 
    包含三个主要的组件:protocol,transport 和 server。 
    其中,protocol 定义了消息是怎样序列化的;transport 定义了消息是怎样在客户端和服务器端之间通信的;server 用于从 transport 接收序列化的消息,根据 protocol 反序列化之,调用用户定义的消息处理器,并序列化消息处理器的响应,然后再将它们写回 transport。

    server 实现: 
    TSimpleServer 
    TNonblockingServer 
    THsHaServer 
    TThreadedSelectorServer 
    TThreadPoolServer 
    对于这几个的区别从名字也可以看的出来几个的区别 
    这边不多加赘述,可以参考下面这篇文章 
    https://github.com/m1ch1/mapkeeper/wiki/Thrift-Java-Servers-Compared

    一般来说,TThreadedSelectorServer 对大多数案例来说都是个安全之选。如果你的系统资源允许运行大量并发线程的话,建议你使用 TThreadPoolServer。

  • 相关阅读:
    一种新的语法研究方法论——构式语法(construction grammar)理论
    男士健身篇
    !!! TCP实现P2P通信、TCP穿越NAT的方法、TCP打洞
    新手怎样学习Flash及as脚本编程? [复制链接]
    UDP穿越NAT原理
    一周七天英语怎么说
    !! 使用正则表达式匹配嵌套Html标签
    优秀老板的特征李开复微博
    搜狐超越新浪给创业者的两个启示:不断+耐心布局
    成大事必备九种手段(没有手段,你永远吃不到成功的甜果)
  • 原文地址:https://www.cnblogs.com/zhaoxinshanwei/p/8573943.html
Copyright © 2020-2023  润新知