一、thift基础
1.1 thrift简介
1.1.1 RPC
RPC 是一种技术思想而非一种规范或协议,常见 RPC 技术和框架有:
- 应用级的服务框架:阿里的 Dubbo/Dubbox、Google gRPC、Spring Boot/Spring Cloud。
- 远程通信协议:RMI、Socket、SOAP(HTTP XML)、REST(HTTP JSON)。
- 通信框架:MINA 和 Netty。
目前流行的开源 RPC 框架还是比较多的,有阿里巴巴的 Dubbo、Facebook 的 Thrift、Google 的 gRPC、Twitter 的 Finagle 等。
在一个典型 RPC 的使用场景中,包含了服务发现、负载、容错、网络传输、序列化等组件,其中“RPC 协议”就指明了程序如何进行网络传输和序列化。
只有二进制数据才能在网络中传输,序列化和反序列化的定义是:
- 将对象转换成二进制流的过程叫做序列化
- 将二进制流转换成对象的过程叫做反序列化
1.1.2 thrift
Thrift是一个跨语言通信的?RPC (Remote Procedure Call Protocol )远程过程调用协议,Thrift 最初是由 Facebook 开发用做系统内各语言之间的 RPC 通信的一个可扩展且跨语言的软件框架,它结合了功能强大的软件堆栈和代码生成引擎,允许定义一个简单的定义文件中的数据类型和服务接口,以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。
是用来进行可伸缩的、跨语言的服务开发,它通过一个代码生成引擎来构建高效、无缝的服务,这些服务能够实现跨语言调度,目前支持的语言有: C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml and Delphi 等。
Thrift重要组件:
(1) protocol: 数据通信协议
(2)transport: 传输方式
对数据格式进行转换的协议
◆TSocket::采用TCP Socket进行数据传输。
◆ TFileTransport:文件(日志)传输类,允许client将文件传给server,允许server 将收到的数据写到文件中。
◆ THttpTransport:采用Http传输协议进行数据传输
◆ TZlibTransport:压缩后对数据进行传输,或者将收到的数据解压
(3) Server Type: 服务端类型
Server将会汇集一下所有功能:
1.创建Transport
2.创建Transport的input、output协议
3.创建基于协议的processor
4.等待传入连接,并将他们交给processor
1.2 使用方法
它提供一种可以直接使用接口,进行不同服务之间通信的方法。
(1)利用其定义的描述性语言(IDL)定义接口。
(2)利用THRIFT bin 文件,将定义的接口转换成指定语言的代码文件。
(3)直接使用转换的代码文件进行服务间通信。
Thrift类型系统包括预定义基本类型,用户自定义结构体,容器类型,异常和服务定义。
1.3 数据类型
1.3.1 基本数据类型
bool: 布尔类型,占一个字节
byte: 有符号字节 //对应C++ char
i16:16位有符号整型 //对应C++ short
i32:32位有符号整型 //对应C++ int
i64:64位有符号整型 //对应C++ long
double:64位浮点数 //对应C++ double
string:未知编码或者二进制的字符串 //对应C++ string
1.3.2 枚举类型
1.编译器默认从0开始赋值
2.可以赋予某个常量某个整数
3.允许常量是十六进制整数
4.末尾无分号或逗号
5.给常量赋缺省值时,使用常量的全称
6.Thrift不支持枚举类嵌套,枚举常量必须是32位的正整数
enum Operation {
ADD = 1,
SUBTRACT = 2,
MULTIPLY = 3,
DIVIDE = 4
}
1.3.3 容器类型
List<t1>:一系列t1类型的元素组成的有序列表,元素可以重复,对应c++中vector
Set<t1>:一些t1类型的元素组成的无序集合,元素唯一不重复,对应c++中set
Map<t1,t2>:key/value对,key唯一,对应c++中map
1.3.4 结构体
1.struct不能继承,但是可以嵌套,不能嵌套自己。
2.其成员都是有明确类型
3.成员是被正整数编号过的,其中的编号使不能重复的,这个是为了在传输过程中编码使用。
4.成员分割符可以是逗号(,)或是分号(;),而且可以混用
5.字段会有optional和required之分和protobuf一样,但是如果不指定则为无类型–可以不填充该值,但是在序列化传输的时候也会序列化进去,optional是不填充则不序列化,required是必须填充也必须序列化。
6.每个字段可以设置默认值
7.同一文件可以定义多个struct,也可以定义在不同的文件,进行include引入。
struct Work {
1: i32 num1 = 0,
2: i32 num2,
3: Operation op,
4: optional string comment,
}
1.4 服务
Thrift中服务定义的方式和语法等同于面向对象语言中定义接口。Thrift编译器会产生实现接口的client和server桩。具体有以下规定:
1.函数定义可以使用逗号或分号标识结束
2.参数可以是基本类型或者结构体,但参数只能是只读的(const),不可以作为返回值
3.返回值可以是基本类型或者结构体
4.返回值可以是void
服务的定义在后文的实例中可以找到。
1.5 异常处理
异常在语法和功能上类似于结构体,只是异常使用关键字exception而不是struct关键字来声明。但它在语义上不同于结构体—当定义一个RPC服务时,开发者可能需要声明一个远程方法抛出一个异常。
exception InvalidOperation {
1: i32 what,
2: string why
}
1.6 常见问题
(1)结构体中使用optional 注意点
写入数据时,需要使用结构体中各字段的__set_ 接口,否则写入数据无法发送。
(2)接口要防止阻塞
二、环境安装
2.1 boost安装
要用thrift必须先安装boost,thrift依赖boost库
参考:ubuntu下安装boost_轮子工厂-CSDN博客_ubuntu安装boost
1、boost下载
安装boost_1_59_0
2、执行脚本
./bootstrap.sh
3、执行./sh
sudo ./b2
4、安装
sudo ./b2 install
2.2 thrift安装
版本说明:
ubuntu 16.04
thrift-0.9.3.tar.gz
1、下载thrift安装包
(1)下载安装包
(2)解压thrift安装包
2、执行配置命令
先进入解压后的thrift安装包
执行配置命令
3、执行编译指令make
4、执行安装命令make install
5、 配置/etc/ld.so.conf文件
将/usr/local/lib添加到ld.so.conf文件中
vim /etc/ld.so.conf
写上如下一句:/usr/local/lib
保存退出,source /etc/ld.so.conf
此时好像还没有生效,执行一下如下语句:
ldconfig
6、查看安装结果
此部分参考:
linux安装thrift_Yabo0815的博客-CSDN博客
三、应用thrift
本部分参考以下链接内容:
Thrift在Windows及Linux平台下的安装和使用示例 - lizhenghn - 博客园
应用说明:创建一个server端和client端程序,client通过hello接口发送自己的名字,server端回复。
1、建立hello.thrift文件
文件内容如下:
service HelloService
{
void hello(1: string name);
}
2、对hello.thrift文件编译
编译指令:
thrift --gen cpp hello.thrift
编译后生成gen-cpp目录
对HelloService_server.skeleton.cpp备份,并拷贝重命名为server.cpp
3、修改server.cpp的内容
class HelloServiceHandler : virtual public HelloServiceIf {
public:
HelloServiceHandler() {
// Your initialization goes here
}
void hello(const std::string& name) {
// Your implementation goes here
// 这里只简单打印出client传入的名称
printf("hello, I got your name %s\n", name.c_str());
}
};
编译server.cpp
g++ -o server hello_constants.cpp HelloService.cpp hello_types.cpp server.cpp -I/usr/local/include/thrift -L/usr/local/lib -lthrift
编译结果如下所示:
4、编写客户端程序
编写client.cpp(此文件由自己新建)
编辑内容如下
#include <stdio.h>
#include <string>
#include "transport/TSocket.h"
#include "protocol/TBinaryProtocol.h"
#include "server/TSimpleServer.h"
#include "transport/TServerSocket.h"
#include "transport/TBufferTransports.h"
#include "hello_types.h"
#include "HelloService.h"
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;
using boost::shared_ptr;
int main()
{
shared_ptr<TTransport> socket(new TSocket("localhost", 9090));
shared_ptr<TTransport> transport(new TBufferedTransport(socket));
shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
HelloServiceClient client(protocol);
try
{
transport->open();
client.hello("cpper.info");
transport->close();
}
catch(TException& tx)
{
printf("ERROR:%s\n",tx.what());
}
}
5、运行测试
在一个窗口开启server
在另一个窗口开启client
测试结果如下所示:
测试成功!
6、对以上应用做进一步分析
文件关系如下:
四、
typedef i32 MyInteger
参考文献: