thrift使用

一、什么是thrift

  Thrift是一种接口描述语言和二进制通讯协议,它被用来定义和创建跨语言的服务。它被当作一个远程过程调用(RPC)框架来使用,是由FaceBook为“大规模跨语言服务开发”而开发的。它通过一个代码生成引擎联合了一个软件栈,来创建不同程度的、无缝的跨平台高效服。后来捐献给apache组织了。

二、thrift的架构  

Thrift包含一套完整的栈来创建客户端和服务端程序。顶层部分是由Thrift定义生成的代码。而服务则由这个文件客户端和处理器代码生成。在生成的代码里会创建不同于内建类型的数据结构,并将其作为结果发送。协议和传输层是运行时库的一部分。有了Thrift,就可以定义一个服务或改变通讯和传输协议,而无需重新编译代码。除了客户端部分之外,Thrift还包括服务器基础设施来集成协议和传输,如阻塞、非阻塞及多线程服务器。栈中作为I/O基础的部分对于不同的语言则有不同的实现。
Thrift支持众多通讯协议:
  • TBinaryProtocol – 一种简单的二进制格式,简单,但没有为空间效率而优化。比文本协议处理起来更快,但更难于调试。
  • TCompactProtocol – 更紧凑的二进制格式,处理起来通常同样高效。
  • TDebugProtocol – 一种人类可读的文本格式,用来协助调试。
  • TDenseProtocol – 与TCompactProtocol类似,将传输数据的元信息剥离。
  • TJSONProtocol – 使用JSON对数据编码。
  • TSimpleJSONProtocol – 一种只写协议,它不能被Thrift解析,因为它使用JSON时丢弃了元数据。适合用脚本语言来解析。
支持的传输协议有:
  • TFileTransport – 该传输协议会写文件。
  • TFramedTransport – 当使用一个非阻塞服务器时,要求使用这个传输协议。它按帧来发送数据,其中每一帧的开头是长度信息。
  • TMemoryTransport – 使用存储器映射输入输出。(Java的实现使用了一个简单的ByteArrayOutputStream。)
  • TSocket – 使用阻塞的套接字I/O来传输。
  • TZlibTransport – 用Zlib执行压缩。用于连接另一个传输协议。
Thrift还提供众多的服务器,包括:
  • TNonblockingServer – 一个多线程服务器,它使用非阻塞I/O(Java的实现使用了NIO通道)。TFramedTransport必须跟这个服务器配套使用。
  • TSimpleServer – 一个单线程服务器,它使用标准的阻塞I/O。测试时很有用。
  • TThreadPoolServer – 一个多线程服务器,它使用标准的阻塞I/O。

三、thrift的使用

  1.下载并安装thrift.exe,然后配置环境变量,使用thrift -version 来验证是否安装成功

  2.编写.thrift文件

  

//名称空间,用来隔离代码,防止数据类型定义中名字冲突
namespace java netty_thrift

//引入其他thrift文件
//include "test.thrift"

/**
数据类型定义,通过typedef将thrift中的类型和java中的类型对应起来,然后直接使用java中的数据类型,方便理解
下面就是thrift中使用的基本数据类型
*/
typedef i16 short
typedef i32 int
typedef i64 long
typedef bool boolean
typedef string String
typedef double double

//定义常量
//const int CONSTANT_A = 12345

/**
定义结构
1.每个属性都有唯一一个正整数标识符
2.每个属性都可以标记为optional和required
3.每个结构体都可以包含其他结构体
4.每个属性都有默认值
5.
*/
struct Person{
    1: optional String username
    2: optional int age
    3: optional boolean married
}


//异常定义
exception DataException{
    1: optional String message
    2: optional String callStack
    3: optional String date
}

//服务定义
service PersonService{

    Person getPersonByName(1: required String username) throws (1: DataException dataException),
    
    void savePerson(1: required Person person)
}


enum TweetType {//仅仅是作为一个例子,后面生成代码时没有用到
 
TWEET,         // 编译器默认从1开始赋值
RETWEET = 2,  // 可以赋予某个常量某个整数
DM = 0xa,     //允许常量是十六进制整数
REPLY         // 末尾没有逗号
}        

  3.生成java代码

    使用命令行thrift -gen java D:WorkSpace1 ettysrc etty_thriftdata.thrift   生成的文件在执行命令时所在的目录。

  4.编写服务端和客户端的代码

    

public class Server {

    public static void main(String[] args) throws TTransportException {
        TNonblockingServerSocket socket = new TNonblockingServerSocket(9999);
        org.apache.thrift.server.THsHaServer.Args args3 = new THsHaServer.Args(socket);
        Processor<PersonServiceImpl> processor = new PersonService.Processor<>(new PersonServiceImpl());
        
        args3.protocolFactory(new TCompactProtocol.Factory());
        args3.transportFactory(new TFramedTransport.Factory());
        args3.processorFactory(new TProcessorFactory(processor));
        
        THsHaServer server = new THsHaServer(args3);
        server.serve();
    }

}
public class PersonServiceImpl implements PersonService.Iface {

    @Override
    public Person getPersonByName(String username) throws DataException, TException {
        Person p = new Person();
        p.setUsername(username);
        p.setAge(28);
        p.setMarried(false);
        return p;
    }

    @Override
    public void savePerson(Person person) throws TException {
        System.out.println(person);
    }

}
public class Client {

    public static void main(String[] args) throws DataException, TException {
        TFramedTransport tFramedTransport = new TFramedTransport(new TSocket("localhost",9999));
        TProtocol protocol = new TCompactProtocol(tFramedTransport);
         netty_thrift.PersonService.Client client = new PersonService.Client(protocol);
         tFramedTransport.open();
        
        Person person = client.getPersonByName("kyle");
        System.out.println(person);
        
        Person p = new Person();
        p.setUsername("xiaoming");
        p.setAge(24);
        p.setMarried(false);
        client.savePerson(p);
        
    }
}