thrift的isset方法
thrift用法
thrift用法
Thrift是一个软件框架,它用于构建跨编程语言的可扩展的服务。
它提供了自动化的RPC(远程过程调用)和序列化,使
不同编程语言的应用程序能够相互通信和交换数据。
Thrift的用法可以分为以下几个方面:
1. 定义数据类型:首先需要使用Thrift的IDL(接口定义语言)来定义数据类型。
IDL是一种类似于结构体定义的语法,用于
描述服务接口和数据类型。
2. 生成代码:使用Thrift提供的编译器,将定义的IDL文件编译成对应的代码,以便在各种编程语言中使用。
Thrift支持多
种编程语言,包括Java、C++、Python等。
3. 实现服务接口:在所选择的编程语言中,根据生成的代码实现服务接口。
这包括定义服务接口的方法,处理客户端的请求,以及返回相应的数据。
4. 启动服务:在服务器上启动Thrift服务,使其能够监听来自
客户端的请求。
可以使用Thrift提供的服务器组件,如TThreadPoolServer、TNonblockingServer等。
5. 客户端调用:在客户端应用程序中使用Thrift客户端库,根
据生成的代码来调用远程服务。
这包括创建一个客户端对象,设置连接参数,调用服务接口的方法,以及处理返回的数据。
通过这些步骤,可以使用Thrift框架来构建跨编程语言的可扩展的服务。
Thrift简析
Thrift简析Thrift源于⼤名⿍⿍的facebook之⼿,在2007年facebook提交Apache基⾦会将Thrift作为⼀个开源项⽬,对于当时的facebook来说创造thrift是为了解决facebook系统中各系统间⼤数据量的传输通信以及系统之间语⾔环境不同需要跨平台的特性。
所以thrift可以⽀持多种程序语⾔,例如: C++, C#, Cocoa, Erlang, Haskell, Java, Ocami, Perl, PHP, Python, Ruby, Smalltalk. 在多种不同的语⾔之间通信thrift可以作为⼆进制的⾼性能的通讯中间件,⽀持数据(对象)序列化和多种类型的RPC服务。
Thrift适⽤于程序对程序静态的数据交换,需要先确定好他的数据结构,他是完全静态化的,当数据结构发⽣变化时,必须重新编辑IDL⽂件,代码⽣成,再编译载⼊的流程,跟其他IDL⼯具相⽐较可以视为是Thrift的弱项,Thrift适⽤于搭建⼤型数据交换及存储的通⽤⼯具,对于⼤型系统中的内部数据传输相对于JSON和xml⽆论在性能、传输⼤⼩上有明显的优势。
Thrift 主要由5个部分组成:类型系统以及 IDL 编译器:负责由⽤户给定的 IDL ⽂件⽣成相应语⾔的接⼝代码TProtocol:实现 RPC 的协议层,可以选择多种不同的对象串⾏化⽅式,如 JSON, Binary。
TTransport:实现 RPC 的传输层,同样可以选择不同的传输层实现,如socket, ⾮阻塞的 socket, MemoryBuffer 等。
TProcessor:作为协议层和⽤户提供的服务实现之间的纽带,负责调⽤服务实现的接⼝。
TServer:聚合 TProtocol, TTransport 和 TProcessor ⼏个对象。
上述的这5个部件都是在 Thrift 的源代码中通过为不同语⾔提供库来实现的,这些库的代码在 Thrift 源码⽬录的 lib ⽬录下⾯,在使⽤ Thrift 之前需要先熟悉与⾃⼰的语⾔对应的库提供的接⼝。
Thrift之TProtocol类体系原理及源码详细解析之类继承架构分析共5页
这部分相关的类主要实现与协议相关的内容,这里说的协议是指对数据传输格式封装的协议,实现不同的协议来适合不同场景下的数据传输,因为在不同的场景下不同协议对于数据传输来说效率有很大的差别。
下面是这个部分相关类的类关系图:由以上类图可以发现所有的协议类都从TProtocol类直接或间接继承,每一个协议类都有一个对应的生产对象工厂(协议工厂)。
TProtocol是一个抽象的类,不能直接使用的,它有一个直接子类默认实现了所有方法(空实现),如果我们需要定义自己的数据传输协议可以直接从这个类继承。
第一节类继承架构分析为什么需要对这部分的类继承架构进行分析了?上面不是有很清楚的类继承关系图了吗?但是Facebook在实现时并不是简单的这样继承下来就可以了,Facebook为了后期协议的可扩展性和允许其他组织、团队或个人实现自己的数据传输(主要是数据格式的封装)协议,里面多加了一层继承关系,就是类图中的TVirtualProtocol类,从类的名称可以看出这是一个虚的协议。
怎样理解这个虚的协议了?通过阅读代码我觉得可以这样理解:因为它定义为一个模板类,这个模板类有两个参数,一个用于数据传输的真正协议,一个是用来继承的,它本身没有对协议具体内容做实现,所以说它是一个虚的协议类。
下面我们对这个类继承架构结合代码实现来具体分析。
1 抽象类TProtocol和默认实现类TProtocolDefaults抽象类对于每一种数据类型都提供了读写的开始和介绍的方法,这里读写方法应该是针对网络IO读写,不过真正实现网络读写还不是这里的方法,这里方法主要处理数据,例如对数据格式做调整。
真正实现网络IO读写是下一章介绍的TTransport相关类实现的,那里还会对传输的方式做相应控制,例如是否压缩。
除了具体的数据类型有写入和读取的方法,消息也是需要通过网络传递,所以也定义了消息的传输读写方法。
当然还定义了一些公用的功能,如跳过某一个结构不读、大小端数据格式调整、主机字节序和网络字节序的相互转换等。
thrift简单示例(基于C++)
thrift简单⽰例(基于C++)这个thrift的简单⽰例, 来源于官⽹ (/tutorial/cpp), 因为我觉得官⽹的例⼦已经很简单了, 所以没有写新的⽰例, 关于安装的教程, 可以参考https:///albizzia/p/10838646.html, 关于thrift⽂件的语法, 可以参考: https:///albizzia/p/10838646.html.thrift⽂件⾸先给出shared.thrift⽂件的定义:/*** 这个Thrift⽂件包含⼀些共享定义*/namespace cpp sharedstruct SharedStruct {1: i32 key2: string value}service SharedService {SharedStruct getStruct(1: i32 key)}然后给出tutorial.thrift的定义:/*** Thrift引⽤其他thrift⽂件, 这些⽂件可以从当前⽬录中找到, 或者使⽤-I的编译器参数指⽰.* 引⼊的thrift⽂件中的对象, 使⽤被引⼊thrift⽂件的名字作为前缀, 例如shared.SharedStruct.*/include "shared.thrift"namespace cpp tutorial// 定义别名typedef i32 MyInteger/*** 定义常量. 复杂的类型和结构体使⽤JSON表⽰法.*/const i32 INT32CONSTANT = 9853const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}/*** 枚举是32位数字, 如果没有显式指定值,从1开始.*/enum Operation {ADD = 1,SUBTRACT = 2,MULTIPLY = 3,DIVIDE = 4}/*** 结构体由⼀组成员来组成, ⼀个成员包括数字标识符, 类型, 符号名, 和⼀个可选的默认值.* 成员可以加"optional"修饰符, ⽤来表明如果这个值没有被设置, 那么他们不会被串⾏化到* 结果中. 不过这个在有些语⾔中, 需要显式控制.*/struct Work {1: i32 num1 = 0,2: i32 num2,3: Operation op,4: optional string comment,}// 结构体也可以作为异常exception InvalidOperation {1: i32 whatOp,2: string why}/*** 服务需要⼀个服务名, 加上⼀个可选的继承, 使⽤extends关键字*/service Calculator extends shared.SharedService {/** * ⽅法定义和C语⾔⼀样, 有返回值, 参数或者⼀些它可能抛出的异常, 参数列表和异常列表的 * 写法与结构体中的成员列表定义⼀致. */void ping(),i32 add(1:i32 num1, 2:i32 num2),i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),/** * 这个⽅法有oneway修饰符, 表⽰客户段发送⼀个请求, 然后不会等待回应. Oneway⽅法 * 的返回值必须是void */oneway void zip()}将上述⽂件放置在同⼀个⽂件夹, 然后编译上述的thrift⽂件:$ thrift -r --gen cpp tutorial.thrift⽣成的⽂件会出现在gen-cpp⼦⽂件夹中, 因为编译时使⽤了-r参数, 所以shared.thrift也会被编译.我们可以考虑查看⼀下thrift编译之后⽣成的⽂件, 这⾥, 我们可以考虑先编译shared.thrift, 编译后, 会⽣成7个⽂件, 分别是shared_constants.h, shared_constants.cpp, shared_types.h, shared_types.cpp, SharedService.h, SharedService.cpp, SharedService_server.skeleton.cpp.我们先查看shared_constants.h和shared.constants.cpp, 这两个⽂件的命名是原先的thrift⽂件名, 加上_constants, 换种⽅式说, 就是xxx.thrift会⽣成xxx_constants.h和xxx_constants.cpp. 查看⼀下这两个⽂件中的内容: 其中会有⼀个类叫做xxxConstants, 在这个类中, 会将常量作为公有成员, 然后可以通过⼀个全局变量g_xxx_constants 访问. ⽽xxx_constants.cpp为类函数的定义, 以及全局变量的定义, 应该⽐较容易理解.关于shared_types.h和shared_types.cpp⽂件, 查看shared_types.h中的内容可以看出, shared_types.h中是thrift⽂件中各种类型的定义, 这个根据⽂件名应该可以⼤致猜出. 其中每⼀个结构体对应两部分, 假设这个结构体叫yyy, 那么第⼀个部分是结构体_yyy__isset,这个结构体会为thrift中yyy的每个字段添加⼀个对应的bool值, 名字相同.第⼆部分是结构体yyy. 这个结构体中包括thrift中yyy的每个字段, 加上_yyy__isset对象. 这个对象⽤于yyy读取输⼊给⾃⾝赋值时, 标识某个字段是否被赋值. yyy中的函数主要有如下⼏个: (1) 默认构造函数 (2) 析构函数 (3) 设置成员变量值的函数 (4) ⽐较函数 (5) read函数, ⽤来读取TProtocol对象的内容, 来给⾃⼰赋值 (6) write函数, 将⾃⾝的值写⼊到TProtocol的对象中. 最后还有⼀个swap函数.关于SharedService.h和SharedService.cpp⽂件, 查看SharedService.h中的内容可以看出, 这个⽂件的⽂件名来⾃于thrift中的service SharedService, 假设服务名叫做zzz, 那么就会⽣成对应的zzz.h和zzz.cpp⽂件, ⽤来实现这个服务的接⼝相关的内容. 查看SharedService.h⽂件, 可以看到如下内容:(1) class SharedServiceIf⽤来实现thrift⽂件中SharedService的接⼝,(2) SharedServiceIfFactory⽤来实现SharedServiceIf的⼯⼚接⼝, 构建函数为getHandler, 释放函数为releaseHandler, 其中SharedServiceIf在⼯⼚类中定义别名Handler.(3) SharedServiceIfSingletonFactory是SharedServiceIfFactory的⼀个具体实现, ⽤来实现返回单例的SharedServiceIf对象.(4) SharedServiceNull是SharedServiceIf的不做任何⾏为的实现.(5) _SharedService_getStruct_args__isset是SharedService服务的getStruct函数的参数对应的isset类, ⽤来表⽰这些参数是否存在.(6) SharedService_getStruct_args是SharedService服务的getStruct函数的参数对应的类, ⽤来表⽰⼀个服务的函数的参数, 实现内容和thrift⽂件中的结构体的实现基本⼀致.(7) SharedService_getStruct_pargs⽤处不太清楚.(8) _SharedService_getStruct_result__isset是SharedService服务的getStruct函数的返回值对应的isset函数, ⽤来表⽰返回值是否设置.(9) SharedService_getStruct_result是SharedService服务的getStruct函数的返回值对应的类, ⽤来表⽰⼀个服务的函数的返回值.(10) _SharedService_getStruct_presult__isset和SharedService_getStruct_presult⽤处不太清楚.(11) SharedServiceClient 是thrift中SharedService服务的客户端实现. SharedServiceClient包括以下内容: 1) 构造函数 2) 获取输⼊和输出Protocol的函数 3) 服务中定义的⽅法, 这⾥是getStruct函数, 以及getStruct函数实现的两个函数, void SharedServiceClient::getStruct(SharedStruct& _return, const int32_t key) { send_getStruct(key); recv_getStruct(_return); } (12) SharedServiceProcessor为编译器⾃动⽣成的对象, 位于Protocol层之上, Server层之下, 实现从输⼊protocol中读取数据, 然后交给具体的Handler处理, 然后再将结果写⼊到输出protocol中. 关于这些联系可以参考 https:///albizzia/p/10884907.html. (13) SharedServiceProcessorFactory是SharedServiceProcessor的⼯⼚类. (14) SharedServiceMultiface是SharedServiceIf的具体实现, 实现了类似于chain of responsiblity的效果, 也就是依次调⽤构造函数中传⼊的多个SharedServiceIf对象的对应⽅法. 参考代码:void getStruct(SharedStruct& _return, const int32_t key) {size_t sz = ifaces_.size();size_t i = 0;for (; i < (sz - 1); ++i) {ifaces_[i]->getStruct(_return, key);}ifaces_[i]->getStruct(_return, key);return;}关于SharedService_server.skeleton.cpp⽂件, 假设thrift中定义的服务名叫做zzz, 那么这个⽂件名叫做zzz_server.skeleton.cpp, skeleton的含义是框架, 这个⽂件的作⽤是告诉我们如何写出thrift服务器的代码. 这个⽂件包括两部分:(1) 类SharedServiceHandler, 这个类⽤来实现SharedServiceIf, 假设thrift中的服务名叫做zzz, 那么这个类的名字就相对的叫做zzzHandler. 这个类会给出如果你想要实现SharedServiceIf, 那么你需要实现的具体的函数, 对于这个类来说, 需要实现构造函数和getStruct函数, getStruct函数是服务中定义的函数, 有时候, 你也需要实现析构函数吧.(2) 然后是⼀个main函数, main函数中的内容, 告诉你怎样实现⼀个简单的thrift服务器. 你可以考虑把这个⽂件拷贝⼀份, 然后根据这个拷贝进⾏修改, 实现服务器的功能.如果把shared.thrift和tutorial.thrift⼀起编译, 那么就会出现14个⽂件, 每个thrift⽂件对应7个, ⽂件的布局和作⽤和之前说明的⼀致.服务端代码#include <thrift/concurrency/ThreadManager.h>#include <thrift/concurrency/PlatformThreadFactory.h>#include <thrift/protocol/TBinaryProtocol.h>#include <thrift/server/TSimpleServer.h>#include <thrift/server/TThreadPoolServer.h>#include <thrift/server/TThreadedServer.h>#include <thrift/transport/TServerSocket.h>#include <thrift/transport/TSocket.h>#include <thrift/transport/TTransportUtils.h>#include <thrift/TToString.h>#include <thrift/stdcxx.h>#include <iostream>#include <stdexcept>#include <sstream>#include "../gen-cpp/Calculator.h"using namespace std;using namespace apache::thrift;using namespace apache::thrift::concurrency;using namespace apache::thrift::protocol;using namespace apache::thrift::transport;using namespace apache::thrift::server;using namespace tutorial;using namespace shared;class CalculatorHandler : public CalculatorIf {public:CalculatorHandler() {}void ping() { cout << "ping()" << endl; }int32_t add(const int32_t n1, const int32_t n2) {cout << "add(" << n1 << ", " << n2 << ")" << endl;return n1 + n2;}int32_t calculate(const int32_t logid, const Work& work) {cout << "calculate(" << logid << ", " << work << ")" << endl;int32_t val;switch (work.op) {case Operation::ADD:val = work.num1 + work.num2;break;case Operation::SUBTRACT:val = work.num1 - work.num2;break;case Operation::MULTIPLY:val = work.num1 * work.num2;break;case Operation::DIVIDE:if (work.num2 == 0) {InvalidOperation io;io.whatOp = work.op;io.why = "Cannot divide by 0";throw io;}val = work.num1 / work.num2;break;default:InvalidOperation io;io.whatOp = work.op;io.why = "Invalid Operation";throw io;}SharedStruct ss;ss.key = logid;ss.value = to_string(val);log[logid] = ss;return val;}void getStruct(SharedStruct& ret, const int32_t logid) {cout << "getStruct(" << logid << ")" << endl;ret = log[logid];}void zip() { cout << "zip()" << endl; }protected:map<int32_t, SharedStruct> log;};/*CalculatorIfFactory is code generated.CalculatorCloneFactory is useful for getting access to the server side of thetransport. It is also useful for making per-connection state. Without thisCloneFactory, all connections will end up sharing the same handler instance.*/class CalculatorCloneFactory : virtual public CalculatorIfFactory {public:virtual ~CalculatorCloneFactory() {}virtual CalculatorIf* getHandler(const ::apache::thrift::TConnectionInfo& connInfo){stdcxx::shared_ptr<TSocket> sock = stdcxx::dynamic_pointer_cast<TSocket>(connInfo.transport);cout << "Incoming connection\n";cout << "\tSocketInfo: " << sock->getSocketInfo() << "\n";cout << "\tPeerHost: " << sock->getPeerHost() << "\n";cout << "\tPeerAddress: " << sock->getPeerAddress() << "\n";cout << "\tPeerPort: " << sock->getPeerPort() << "\n";return new CalculatorHandler;}virtual void releaseHandler( ::shared::SharedServiceIf* handler) {delete handler;}};int main() {TThreadedServer server(stdcxx::make_shared<CalculatorProcessorFactory>(stdcxx::make_shared<CalculatorCloneFactory>()), stdcxx::make_shared<TServerSocket>(9090), //portstdcxx::make_shared<TBufferedTransportFactory>(),stdcxx::make_shared<TBinaryProtocolFactory>());/*// if you don't need per-connection state, do the following insteadTThreadedServer server(stdcxx::make_shared<CalculatorProcessor>(stdcxx::make_shared<CalculatorHandler>()),stdcxx::make_shared<TServerSocket>(9090), //portstdcxx::make_shared<TBufferedTransportFactory>(),stdcxx::make_shared<TBinaryProtocolFactory>());*//*** Here are some alternate server types...// This server only allows one connection at a time, but spawns no threadsTSimpleServer server(stdcxx::make_shared<CalculatorProcessor>(stdcxx::make_shared<CalculatorHandler>()),stdcxx::make_shared<TServerSocket>(9090),stdcxx::make_shared<TBufferedTransportFactory>(),stdcxx::make_shared<TBinaryProtocolFactory>());const int workerCount = 4;stdcxx::shared_ptr<ThreadManager> threadManager =ThreadManager::newSimpleThreadManager(workerCount);threadManager->threadFactory(stdcxx::make_shared<PlatformThreadFactory>());threadManager->start();// This server allows "workerCount" connection at a time, and reuses threadsTThreadPoolServer server(stdcxx::make_shared<CalculatorProcessorFactory>(stdcxx::make_shared<CalculatorCloneFactory>()), stdcxx::make_shared<TServerSocket>(9090),stdcxx::make_shared<TBufferedTransportFactory>(),stdcxx::make_shared<TBinaryProtocolFactory>(),threadManager);*/cout << "Starting the server..." << endl;server.serve();cout << "Done." << endl;return0;}上述代码应该很容易理解, 在这⾥就不解释了.客户端代码#include <iostream>#include <thrift/protocol/TBinaryProtocol.h>#include <thrift/transport/TSocket.h>#include <thrift/transport/TTransportUtils.h>#include <thrift/stdcxx.h>#include "../gen-cpp/Calculator.h"using namespace std;using namespace apache::thrift;using namespace apache::thrift::protocol;using namespace apache::thrift::transport;using namespace tutorial;using namespace shared;int main() {stdcxx::shared_ptr<TTransport> socket(new TSocket("localhost", 9090));stdcxx::shared_ptr<TTransport> transport(new TBufferedTransport(socket));stdcxx::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));CalculatorClient client(protocol);try {transport->open();client.ping();cout << "ping()" << endl;cout << "1 + 1 = " << client.add(1, 1) << endl;Work work;work.op = Operation::DIVIDE;work.num1 = 1;work.num2 = 0;try {client.calculate(1, work);cout << "Whoa? We can divide by zero!" << endl;} catch (InvalidOperation& io) {cout << "InvalidOperation: " << io.why << endl;// or using generated operator<<: cout << io << endl;// or by using std::exception native method what(): cout << io.what() << endl;}work.op = Operation::SUBTRACT;work.num1 = 15;work.num2 = 10;int32_t diff = client.calculate(1, work);cout << "15 - 10 = " << diff << endl;// Note that C++ uses return by reference for complex types to avoid// costly copy constructionSharedStruct ss;client.getStruct(ss, 1);cout << "Received log: " << ss << endl;transport->close();} catch (TException& tx) {cout << "ERROR: " << tx.what() << endl;}}从上⾯的客户端调⽤来看, ⽅法调⽤和本地的类对象的调⽤很相似, thrift的设计算是很巧妙的. ⾥⾯的代码应该不复杂, 所以也不进⾏具体的讲解了.查看⼀下CMakeLists.txt⽂件:cmake_minimum_required(VERSION 2.8)#include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")#Make sure gen-cpp files can be includedinclude_directories("${CMAKE_CURRENT_BINARY_DIR}")include_directories("${CMAKE_CURRENT_BINARY_DIR}/gen-cpp")include_directories("${PROJECT_SOURCE_DIR}/lib/cpp/src")set(tutorialgencpp_SOURCESgen-cpp/Calculator.cppgen-cpp/SharedService.cppgen-cpp/shared_constants.cppgen-cpp/shared_types.cppgen-cpp/tutorial_constants.cppgen-cpp/tutorial_types.cpp)add_library(tutorialgencpp STATIC ${tutorialgencpp_SOURCES})target_link_libraries(tutorialgencpp thrift)add_custom_command(OUTPUT gen-cpp/Calculator.cpp gen-cpp/SharedService.cpp gen-cpp/shared_constants.cpp gen-cpp/shared_types.cpp gen-cpp/tutorial_constants.cpp gen-cpp/tutorial_types.cpp COMMAND ${THRIFT_COMPILER} --gen cpp -r ${PROJECT_SOURCE_DIR}/tutorial/tutorial.thrift)add_executable(TutorialServer CppServer.cpp)target_link_libraries(TutorialServer tutorialgencpp)if (ZLIB_FOUND)target_link_libraries(TutorialServer ${ZLIB_LIBRARIES})endif ()add_executable(TutorialClient CppClient.cpp)target_link_libraries(TutorialClient tutorialgencpp)if (ZLIB_FOUND)target_link_libraries(TutorialClient ${ZLIB_LIBRARIES})endif ()编译运⾏, 我这边启动客户端和服务端的命令分别是:$ LD_LIBRARY_PATH=/usr/local/lib ./TutorialServer$ LD_LIBRARY_PATH=/usr/local/lib ./TutorialClient注: 上述代码可以在thrift源代码中的tutorial/cpp⽂件夹找到.。
thrift基本语法知识
容器中的元素类型可以是任何一种 Thrift 类型。 (4) 异常
异常在功能上等同于 structs,有一点例外是:异常可以继承目标编程语言的异常类,目的是与给定编 程语言的异常处理功能无缝的结合。 (5) 服务
服务是通过 Thrift 类型定义的。服务的定义在语义上与面向对象编程中的接口定义等同。Thrift 编译
Thrift学习笔记—IDL基本类型
Thrift学习笔记—IDL基本类型thrift 采⽤IDL(Interface Definition Language)来定义通⽤的服务接⼝,并通过⽣成不同的语⾔代理实现来达到跨语⾔、平台的功能。
在thrift的IDL中可以定义以下⼀些类型:基本数据类型,结构体,容器,异常、服务1基本类型bool: 布尔值 (true or false), one bytebyte: 有符号字节i16: 16位有符号整型i32: 32位有符号整型i64: 64位有符号整型double: 64位浮点型string: Encoding agnostic text or binary string基本类型中基本都是有符号数,因为有些语⾔没有⽆符号数,所以Thrift不⽀持⽆符号整型。
2特殊类型binary: Blob (byte array) a sequence of unencoded bytes这是string类型的⼀种变形,主要是为使⽤,⽬前我主要使⽤C++的语⾔,所以java的这个类型没有⽤过3structthrift中struct是定义为⼀种对象,和⾯向对象语⾔的class差不多.,但是struct有以下⼀些约束:struct不能继承,但是可以嵌套,不能嵌套⾃⼰。
其成员都是有明确类型成员是被正整数编号过的,其中的编号使不能重复的,这个是为了在传输过程中编码使⽤。
成员分割符可以是逗号(,)或是分号(;),⽽且可以混⽤,但是为了清晰期间,建议在定义中只使⽤⼀种,⽐如C++学习者可以就使⽤分号(;)。
字段会有optional和required之分和protobuf⼀样,但是如果不指定则为⽆类型—可以不填充该值,但是在序列化传输的时候也会序列化进去,optional是不填充则部序列化,required是必须填充也必须序列化。
每个字段可以设置默认值同⼀⽂件可以定义多个struct,也可以定义在不同的⽂件,进⾏include引⼊。
python使用thrift教程的方法示例
python使用thrift教程的方法示例Python使用Thrift的教程Apache Thrift是一个开源的跨语言的RPC框架,它允许不同编程语言之间进行无缝通信。
在本教程中,我们将深入了解如何在Python中使用Thrift框架进行开发。
1. 安装Thrift首先,我们需要安装Thrift框架。
在命令行中运行以下命令来安装Thrift:```pip install thrift```安装完成后,我们将能够在Python项目中使用Thrift。
2.创建服务定义文件接下来,我们需要创建一个Thrift服务定义文件,它描述了我们的RPC接口和数据结构。
我们将创建一个简单的示例,其中包含一个用于加法运算的接口。
创建一个名为calculator.thrift的文件,并将以下内容添加到其中:```namespace py calculatorservice CalculatorServicei32 add(1:i32 num1, 2:i32 num2),```在上面的示例中,我们定义了一个名为CalculatorService的服务,其中包含一个add方法,该方法接受两个整数参数并返回它们的和。
3. 生成Python代码为了使用Thrift定义的接口,在我们能够在Python中调用它们之前,我们需要生成相应的代码。
在命令行中运行以下命令来生成Python代码:```thrift --gen py calculator.thrift```这将生成一个名为gen-py的目录,其中包含了由Thrift定义生成的Python代码。
我们将在下一步中使用这些代码。
4.创建服务实现现在,我们将实现我们在接口中定义的方法。
在Python中,我们可以通过继承Thrift生成的代码中的接口类来实现这些方法。
打开calculator.py文件,并将以下内容添加到文件中:```pythonfrom thrift import Thriftfrom thrift.transport import TSocketfrom thrift.transport import TTransportfrom thrift.protocol import TBinaryProtocolfrom gen_py.calculator import CalculatorServicefrom gen_py.calculator.ttypes import calculatorclass CalculatorHandler:def add(self, num1, num2):result = num1 + num2return resulthandler = CalculatorHandlerprocessor = CalculatorService.Processor(handler)transport = TSocket.TServerSocket(port=9090)tfactory = TTransport.TBufferedTransportFactorypfactory = TBinaryProtocol.TBinaryProtocolFactoryserver = TServer.TSimpleServer(processor, transport, tfactory, pfactory)server.serve```在上面的示例中,我们首先导入了一些必要的库和模块,然后创建了一个名为CalculatorHandler的类。
Thrift序列化与反序列化的实现机制分析
Thrift序列化与反序列化的实现机制分析Thrift是如何实现序死化与反序列化的,在IDL⽂件中,更改IDL⽂件中的变量序号或者[使⽤默认序号的情况下,新增变量时,将新增的变量不放在IDL⽂件的结尾,均会导致Thrift⽂件的反序列后⽆法做到向后兼容],我们只有理解Thrift是如何实现序列化的,才能了解这种现象产⽣的原因,才能把代码写的更让⼈放⼼关于Thrift域的版本号的定义可以在这篇⽂章中找到说定义Versioning in Thrift is implemented via field identifiers.The field header for every member of a struct in Thrift isencoded with a unique field identifier. The combination ofthis field identifier and its type specifier is used touniquely identify the field. The Thrift definition languagesupports automatic assignment of field identifiers,but it is good programming practice to always explicitlyspecify field identifiers.翻译过来,⼤概意思就是⼀个版本号,这个版本号是由属性的数字序号+属性的类型来确定的⼀个简单的Thrift⽂件struct Test {1 : required i32 key;2 : required string value;}执⾏thrift -gen java Test.thrift将thrift⽂件转换成java源⽂件,在此不列出详细的源⽂件内容,只列出与序列化与反序列化相关的代码序列化,实际上就是write,如下所⽰///b/pengpeng/24public void write(org.apache.thrift.protocol.TProtocol oprot, Test struct) throws org.apache.thrift.TException {struct.validate();oprot.writeStructBegin(STRUCT_DESC);oprot.writeFieldBegin(KEY_FIELD_DESC);oprot.writeI32(struct.key);oprot.writeFieldEnd();if (struct.value != null) {oprot.writeFieldBegin(VALUE_FIELD_DESC);oprot.writeString(struct.value);oprot.writeFieldEnd();}oprot.writeFieldStop();oprot.writeStructEnd();}struct.validate()主要⽤来校验thrift⽂件中定义的required域即必传的值是不是有值,没有值就会抛出TProtocolException异常public void validate() throws org.apache.thrift.TException {// check for required fields// alas, we cannot check 'key' because it's a primitive and you chose the non-beans generator.if (value == null) {throw new org.apache.thrift.protocol.TProtocolException("Required field 'value' was not present! Struct: " + toString());}}oprot.writeStructBegin(STRUCT_DESC);STRUCT_DESC = new org.apache.thrift.protocol.TStruct("Test");即开始写结构体的标识,在这⾥我们以TBinaryProtocol⼆进制的传输作为例⼦,TBinaryProtocol中writeStructBegin的实现如下public void writeStructBegin(TStruct struct) {}即什么都没有做,接下来oprot.writeFieldBegin(KEY_FIELD_DESC);中KEY_FIELD_DESC = new org.apache.thrift.protocol.TField("key", org.apache.thrift.protocol.TType.I32, (short)1);TBinaryProtocol中对应的实现如下public void writeFieldBegin(TField field) throws TException {this.writeByte(field.type);this.writeI16(field.id);}从上⾯的代码中可以看出序列化的过程中写⼊的是域的类,从org.apache.thrift.protocol.TType中,我们也可以知道在thrift IDL⽀持的数据类型,如下所⽰public final class TType {public static final byte STOP = 0;public static final byte VOID = 1;public static final byte BOOL = 2;public static final byte BYTE = 3;public static final byte DOUBLE = 4;public static final byte I16 = 6;public static final byte I32 = 8;public static final byte I64 = 10;public static final byte STRING = 11;public static final byte STRUCT = 12;public static final byte MAP = 13;public static final byte SET = 14;public static final byte LIST = 15;public static final byte ENUM = 16;public TType() {}其中STOP⽤于序列化完所有的域后,,表⽰所有的域都序列化完成,接下来是oprot.writeI32(struct.key);这条语句就是写⼊要序列化的int类型值,对应TBinaryProtocol的实现如下所⽰:public void writeI32(int i32) throws TException {this.i32out[0] = (byte)(255 & i32 >> 24);this.i32out[1] = (byte)(255 & i32 >> 16);this.i32out[2] = (byte)(255 & i32 >> 8);this.i32out[3] = (byte)(255 & i32);this.trans_.write(this.i32out, 0, 4);}⼤致意思就是将int转换为byte数组,写⼊下层的channel中,接下来就是oprot.writeFieldEnd();对应TBinaryProtocol的实现如下所⽰:public void writeFieldEnd() {}接下来的这段代应就是序列化Test.thrift中定义的value,和上⾯的序列化过程基本类似,但是也有区别,在序列化string类型时,会先在序死化⽂件⾥写⼊字符串的长度,然后再写⼊字符串的值if (struct.value != null) {oprot.writeFieldBegin(VALUE_FIELD_DESC);oprot.writeString(struct.value);oprot.writeFieldEnd();}最后,会向序列化的⽂件⾥⾯写⼊⼀个字节的0表⽰序列化结束,如下所⽰public void writeFieldStop() throws TException {this.writeByte((byte)0);}从上⾯的序列化过程中,我们可以知道序列化后的⽂件⾥⾯只有域的类型以及域的数字序号,没有域的名称,因此与JSON/XML这种序列化⼯具相⽐,thrift序列化后⽣成的⽂件体积要⼩很多有了序列化的⽣成过程,再来看看thrift是如何反序列化,就⾮常简单了,反序列化的代码如下所⽰public void read(org.apache.thrift.protocol.TProtocol iprot, Test struct) throws org.apache.thrift.TException {org.apache.thrift.protocol.TField schemeField;iprot.readStructBegin();while (true){schemeField = iprot.readFieldBegin();if (schemeField.type == org.apache.thrift.protocol.TType.STOP) {break;}switch (schemeField.id) {case 1: // KEYif (schemeField.type == org.apache.thrift.protocol.TType.I32) {struct.key = iprot.readI32();struct.setKeyIsSet(true);} else {org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);}break;case 2: // VALUEif (schemeField.type == org.apache.thrift.protocol.TType.STRING) {struct.value = iprot.readString();struct.setValueIsSet(true);} else {org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);}break;default:org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);}iprot.readFieldEnd();}iprot.readStructEnd();// check for required fields of primitive type, which can't be checked in the validate methodif (!struct.isSetKey()) {throw new org.apache.thrift.protocol.TProtocolException("Required field 'key' was not found in serialized data! Struct: " + toString());}struct.validate();}反序列化最为核⼼的代码在while循环这⾥,schemeField是由域的类型type及域的数字序号id构成的⼀个类,如下所⽰public class TField {public final String name;public final byte type;public final short id;public TField() {this("", (byte)0, (short)0);}public TField(String n, byte t, short i) { = n;this.type = t;this.id = i;}public String toString() {return "<TField name:\'" + + "\' type:" + this.type + " field-id:" + this.id + ">";}public boolean equals(TField otherField) {return this.type == otherField.type && this.id == otherField.id;}}iprot.readFieldBegin();就是从序列化⽂件中构造⼀个TField类型的对象,TBinaryProtocol的实现如下所⽰,从下⾯的源代码可以看出,⾸先读取域的类型,然后读取域的数字序号public TField readFieldBegin() throws TException {byte type = this.readByte();short id = type == 0?0:this.readI16();return new TField("", type, id);}构造完了TFiled对象之后,我们需要读取域的值,看switch语句,也很容易理解,要读取域的值,需要两个前提1.域的数字序号相同2.域的类型相同在满⾜上⾯的两个要求的前提下型,调⽤相应的读取⽅法,如果域的数字序号相同,但是域的类型不同,则会跳过给该域赋值,执⾏的代码逻辑是org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);最后,反序列化完成后,还要需检查⼀下必传的值是否已经传了,调⽤下⾯这段代码struct.validate();由反序列化的过程,可以知道,Thrift的反序列化,没有⽤到java的反射技术,也没有开设过多的内存空间,因此同JSON/XML相⽐,反序列化更快,更省内存,从反序列化的过程中,我们可以看到Thrift的向后兼容性,需要满⾜⼀定的条件1.域的数字序号不能改变2.域的类型不能改变满⾜了上⾯的两点,⽆论你增加还是删除域,都可以实现向后兼容,勿需担⼼ 。
Thrift使用指南董的博客
Thrift使用指南董的博客1. 内容概要本文档比较全面的介绍了thrift(关于thrift框架的介绍,参考我这篇文章:Thrift框架介绍)语法,代码生成结构和应用经验。
本文主要讲述的对象是thrift文件,并未涉及其client和server的编写方法(关于client和server的编写方法,可参考我这篇文章:使用Thrift RPC编写程序)。
本文档大部分内容翻译自文章:“Thrift:The missing Guide“。
2. 语法参考2.1 TypesThrift类型系统包括预定义基本类型,用户自定义结构体,容器类型,异常和服务定义(1) 基本类型bool:布尔类型(true or value),占一个字节byte:有符号字节i16:16位有符号整型i32:32位有符号整型i64:64位有符号整型double:64位浮点数string:未知编码或者二进制的字符串注意,thrift不支持无符号整型,因为很多目标语言不存在无符号整型(如java)。
(2) 容器类型Thrift容器与类型密切相关,它与当前流行编程语言提供的容器类型相对应,采用java泛型风格表示的。
Thrift提供了3种容器类型:List<t1>:一系列t1类型的元素组成的有序表,元素可以重复Set<t1>:一系列t1类型的元素组成的无序表,元素唯一Map<t1,t2>:key/value对(key的类型是t1且key唯一,value类型是t2)。
容器中的元素类型可以是除了service意外的任何合法thrift类型(包括结构体和异常)。
(3) 结构体和异常Thrift结构体在概念上同C语言结构体类型—-一种将相关属性聚集(封装)在一起的方式。
在面向对象语言中,thrift结构体被转换成类。
异常在语法和功能上类似于结构体,只不过异常使用关键字exception而不是struct关键字声明。
Thrift之TProcess类体系原理及源码详细解析
Thrift之TProcess类体系原理及源码详细解析之前对Thrift自动生成代码的实现细节做了详细的分析,下面进行处理层的实现做详细分析了!会利用到自动代码生成的知识。
这部分是协议层和用户提供的服务实现之间的纽带,定义了调用服务实现的接口框架,真正实现某种服务接口是通过上一章介绍的代码生成工具生成的代码。
本章将介绍这个框架的基本原理,然后通过生成的一个实例来具体介绍怎样完成一次完整的服务,这个可能涉及到下面章节的一些知识,对于这些知识不详细分析其功能,只是介绍它在其中起什么作用。
选择的实例是Facebook内部用这个框架实现的一个分布式日志收集系统scribe。
下面是这部分相关类的类关系图:从上图中可以看出TProcessor是这个部分的顶层基类,其他之类基本上都是通过Thrift代码生成工具生成的,只有少数是为了扩展一些功能而直接写代码实现,如PeekProcessor类就增加了一些对原始数据处理的功能。
scribeProcessor和FacebookServiceProcessor类就是用代码生成器根据IDL文件生成的,也是我们后面需要分析的一个实例。
第一节服务接口调用框架分析这个基本的框架包括三个类,一个就是抽象类TProcessor,负责调用用户定义的服务接口,从一个接口读入数据,写入一个输出接口。
一个最主要的函数定义如下:1 virtual bool process(boost::shared_ptr<protocol::TProtocol> in,23 boost::shared_ptr<protocol::TProtocol> out, void* connectionContext) = 0;这个函数是一个纯虚函数,所以继承这个类的子类都必须实现这个函数,这个函数就是最主要的数据传输功能。
第二个类就是负责处理TProcessor类产生的事件的类TProcessorEventHandler,主要定义了一些当某事件发生时的处理函数,例如当读取参数之前可以做一些处理功能。
php中isset的用法
PHP中isset的用法一、什么是i s s e t函数在P HP中,is se t是一个用于判断变量是否设置并且非n ull的函数。
它返回一个布尔值,如果变量存在且有值,则返回tr ue,否则返回f a ls e。
二、使用i sset函数的场景1.判断变量是否存在在开发中,我们经常需要判断一个变量是否已经被定义。
通过使用i s se t函数,我们可以轻松地进行变量存在性的判断。
$v ar=123;i f(i ss et($va r)){e c ho"变量已定义";}e ls e{e c ho"变量未定义";}输出:>变量已定义2.判断数组元素是否存在在处理数组时,我们常常需要判断数组中的某个元素是否存在。
i s se t函数可以帮助我们快速进行判断。
$a rr=a rr ay("ap ple","ba na na","o ran g e");i f(i ss et($ar r[0])){e c ho"数组元素存在";}e ls e{e c ho"数组元素不存在";}输出:>数组元素存在3.避免访问不存在的属性或方法当我们使用对象编程时,有时会遇到调用一个不存在的属性或方法的情况。
使用i ss et函数可以在调用之前进行判断,避免出现错误。
c l as sF ru it{p u bl ic$n am e="a ppl e";}$f ru it=n ew Fr ui t();i f(i ss et($fr ui t->c ol or)){e c ho$f ru it->co lor;}e ls e{e c ho"属性不存在";}输出:>属性不存在三、i s s e t函数的性能注意事项在使用i ss et函数的时候,需要注意其对性能的影响。
thrift 协议
thrift 协议Thrift 协议。
Thrift 是一个跨语言的远程服务调用框架,它可以用于构建高效的、可扩展的服务。
Thrift 协议是 Thrift 框架中的一部分,它定义了客户端和服务器之间通信的规范。
在本文中,我们将详细介绍 Thrift 协议的相关内容,包括其特点、使用方法和优势。
首先,让我们来了解一下 Thrift 协议的特点。
Thrift 协议是一种二进制协议,它将数据序列化为紧凑的二进制格式,这样可以减少数据传输的大小,提高传输效率。
与其他文本协议相比,Thrift 协议的性能更好,尤其在处理大量数据时表现更为突出。
此外,Thrift 协议还支持多种数据类型,包括整型、浮点型、布尔型、字符串等,可以满足不同类型数据的传输需求。
在实际应用中,我们可以通过以下步骤来使用 Thrift 协议。
首先,我们需要定义一个 Thrift 文件,其中包括数据结构的定义、服务接口的定义等内容。
然后,利用 Thrift 提供的代码生成工具,根据 Thrift 文件生成对应的客户端和服务器代码。
接下来,我们可以在客户端和服务器端分别调用生成的代码,实现数据的序列化和反序列化,以及远程服务的调用。
通过这些步骤,我们就可以很方便地使用 Thrift 协议进行远程服务调用了。
与其他远程服务调用框架相比,Thrift 协议具有许多优势。
首先,它支持多种编程语言,包括 Java、C++、Python 等,这使得不同语言的系统可以很方便地进行交互。
其次,Thrift 协议具有良好的跨平台性,可以在不同操作系统上运行,这为系统的部署和维护带来了便利。
此外,Thrift 协议还具有良好的扩展性,可以很方便地支持新的数据类型和服务接口,满足系统不断发展的需求。
总的来说,Thrift 协议是一个高效、可扩展的远程服务调用协议,它具有二进制传输、多语言支持、跨平台性和良好的扩展性等特点。
通过使用 Thrift 协议,我们可以很方便地实现不同系统之间的远程服务调用,提高系统的性能和可扩展性。
thrift入门简介
[一]、概述 Thrift 是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎,以构
建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 等等 编程语言间无缝结合的、高效的服务。
11
12 /**
13 *
14 * 15 * @author Michael 16 *
17 */
18 public class HelloServerDemo {
19
public static final int SERVER_PORT = 8090;
20
21
public void startServer() {
13
}
14
15
@Override
16
public String sayHello(String username) throws TException {
17
return "Hi," + username + " welcome to my blog ";
18
}
4 / 22
19 20 } 21
3.TSimpleServer 服务端 简单的单线程服务模型,一般用于测试。 编写服务端 server 代码:HelloServerDemo.java
35
tArgs.processor(tprocessor);
36
tArgs.protocolFactory(new TBinaryProtocol.Factory());
thrift介绍
thrift介绍⼀描述thrift(个⼈英语飘过六级,翻译的肯定不是很准确,请谅解。
) Apache thrift框架,旨在处理扩语⾔的开发服务,它结合代码⽣产引擎的软件栈,构建⾼效地和⽆缝地运⾏在C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml和Delphi等语⾔中的服务。
⼆⽂件说明和使⽤⽅式(thrift通过⼀个中间语⾔IDL(接⼝定义语⾔)来定义RPC的数据类型和接⼝) 我们需要定义⼀个thrift⽂件,这个⽂件是由thrift tpe(相当于实体类,也可以理解为使我们需要进⾏服务间传递的消息)和Service(这个Service就相当于⼀个service类,中间有各种⽅法)构成的接⼝定义⽂件。
⽂件中定义的Service将有服务端进⾏实现,并由客户端进⾏调⽤。
thrift编辑器将你定义的thrift⽂件⽣产为你客户端和服务端使⽤的资源⽂件。
通过运⾏thrift --gen <language> <Thrift filename>来⽣产资源⽂件。
--language是你使⽤的编程语⾔。
--Thrift filename⽣产⽂件的位置三协议栈结构 最上层是⽤户⾃⾏实现的业务逻辑代码.第⼆层是由thrift编译器⾃动⽣成的代码,主要⽤于结构化数据的解析,发送和接收。
TServer主要任务是⾼效的接受客户端请求,并将请求转发给Processor处理。
Processor负责对客户端的请求做出响应,包括RPC请求转发,调⽤参数解析和⽤户逻辑调⽤,返回值写回等处理。
从TProtocol以下部分是thirft的传输协议和底层I/O通信。
TProtocol是⽤于数据类型解析的,将结构化数据转化为字节流给TTransport进⾏传输。
Thrift 简单介绍
Thrift 是什么?Thrift源于大名鼎鼎的facebook之手,在2007年facebook提交Apache基金会将Thrift作为一个开源项目,对于当时的facebook来说创造thrift是为了解决facebook系统中各系统间大数据量的传输通信以及系统之间语言环境不同需要跨平台的特性。
所以thrift可以支持多种程序语言,例如: C++, C#, Cocoa, Erlang, Haskell, Java, Ocami, Perl, PHP, Python, Ruby, Smalltalk. 在多种不同的语言之间通信thrift可以作为二进制的高性能的通讯中间件,支持数据(对象)序列化和多种类型的RPC服务。
Thrift适用于程序对程序静态的数据交换,需要先确定好他的数据结构,他是完全静态化的,当数据结构发生变化时,必须重新编辑IDL文件,代码生成,再编译载入的流程,跟其他IDL工具相比较可以视为是Thrift的弱项,Thrift适用于搭建大型数据交换及存储的通用工具,对于大型系统中的内部数据传输相对于JSON和xml无论在性能、传输大小上有明显的优势。
Thrift是IDL(interface definition language)描述性语言的一个具体实现,关于IDL的话题我们可以追溯到CORBA 盛行1999-2001年(Common Object Request Broker Architecture/公用对象请求代理体系结构),在IDL 中我们似乎不会忘记到这几个关键字:module、interface、string、long 和int,我还记得IDL利用module来创建名称空间,并且准确地映射为Java 的package,这些特性几乎和现在thrift的特性完全相同,所以thrift的设计思想和理念绝不是什么从火星来的new idea,看看在那个CORBA盛行的年代人们提出的概念,如图所示CORBA 请求的各个部分,回头我们再与thrift进行对比一下:Thrift 基础架构Thrift是一个服务端和客户端的架构体系,从我个人的感官上来看Thrift是一个类似XML-RPC+Java-to- IDL+Serialization Tools=Thrift 的东东,Thrift 具有自己内部定义的传输协议规范(TProtocol)和传输数据标准(TTransports),通过IDL脚本对传输数据的数据结构(struct) 和传输数据的业务逻辑(service)根据不同的运行环境快速的构建相应的代码,并且通过自己内部的序列化机制对传输的数据进行简化和压缩提高高并发、大型系统中数据交互的成本,下图描绘了Thrift的整体架构,分为6个部分:1.你的业务逻辑实现(You Code) 2.客户端和服务端对应的Service 3.执行读写操作的计算结果4.TProtocol 5.TTransports 6.底层I/O通信图中前面3个部分是1.你通过Thrift脚本文件生成的代码,2.图中的褐色框部分是你根据生成代码构建的客户端和处理器的代码,3.图中红色的部分是2 端产生的计算结果。
Thrift源码学习一——源码结构
Thrift源码学习⼀——源码结构Thrift 客户端与服务端的交互图源码结构1. 传输层 TTransport:1. TTransport:客户端传输层抽象基础类,read、write、flush、close 等⽅法2. TSocket 与 TNonBlockingSocket:分别是基于 BIO 和 NIO 客户端传输类3. TServerSocket 与 TNonBlockingServerSocket:分别是基于 BIO 和 NIO 服务端传输类4. TZlibTransport:5. TSaslClientTransport 与 TSaslServerTransport:提供 SSL 校验2. 协议层 Protocol:1. TBinaryProtocol:⼆进制流传输协议类,把各类型转换成 byte 数组,交给 TTransport 传输2. TCompactProtocol:使⽤ Variable-Length Quantity(VLQ)编码对数据进⾏压缩(压缩⽅法⼆进制协议类,将 Integer 按 ZigZag 压缩)3. TTupleProtocol:继承⾃ TCompactProtocol,Struct 使⽤时更省空间4. TJSONProtocol:JSON 格式协议类,将数据封装成 JSON 格式,再转成 byte 数组交给传输层5. TSimpleJSONProtocol:JSON 格式协议类,但只⽀持写的功能3. 处理层 Processor:1. TProcessor:基础接⼝,process(TProtocol in, TProtocol out)2. TBaseProcessor:基础抽象类,持有 processMap 对象,key 为⽅法名,value 为⽅法3. Processor:由声明的 IDL ⽣成,实现 TProcessor 接⼝并继承了 TBaseProcessor 类4. TAsyncProcessor:异步处理接⼝5. TBaseAsyncProcessor:异步处理抽象类6. AsyncProcessor:由声明的 IDL ⽣成,实现 TAsyncProcessor 接⼝并继承 TAsyncProcessor 类4. 服务层 Server:1. TServer:基础抽象类,类似⼀个容器,持有 TProcessor、TTransport、TProtocol 的⼯⼚对象,提供 server() ⽅法,⽤于启动服务,stop() ⽤于停⽌服务2. TSimpleServer:单线程阻塞式服务3. TNonblockingServer:⽀持⾮阻塞单线程服务模型,基于 NIO 的 select 实现4. TThreadPoolServer:专门的线程接受请求并交给线程池处理,阻塞式线程池模型。
thrift基本语法知识
除此之外,还有一类特殊类型:
1.Leabharlann binary:未编码的 bytes 序列
(2) 结构体 Thrift 结构体用于定义一个普通的对象——它们本质上等价于面向对象编程(OOP)语言中的 classes,但
是 thrift 结构体之间不能继承。每个结构体都有一组类型定义的字段,每个 field 都有一个唯一的命名标识 符。 (3) 容器
2 Thrift 接口定义语言
Thrift 接口定义语言(IDL, Interface Definition Language)中允许使用的是 thrift types。每个 thrift 文件主 要有 hearder,类型定义,异常及服务组成。下面详细介绍 thrift 文件的组成:
每个 thrift 文档包含 0 个或多个 headers 以及 0 个或多个 definitions。 2.1 Header
include “../../***.thrift” 结果:被引用的 thrift 文件产生的代码中的头文件即可包含在 thrift 产生的代码的头部,使得其能够使 用、访问。 (2) C++ include C++ include 能够将 C++定义的头文件添加到该 thrift 文件产生的 C++代码中。 语法: cpp_include “../../***.h” 结果:被引用的.h 文件将包含到 thrift 产生的代码的头部。 (3) namespace namespace 的声明方式采用为 namespaces/package/module/etc。namespace scope 表示该 namespace 应用 于哪种编程语言,若 scope 的取值为“*”,则表示该 namespace 适用于所有的目标语言。 语法: namespace namespaceScope 名称。 其中,namespaceScope 的取值有 * | cpp | java | py | perl | rb | cocoa | csharp e.g namespace cpp test 2.2 Definition thrift 中可以定义的类型有 const | typedef | enum | struct | exception | service (1) const 语法:
redisson trysetrate 和setrate方法
redisson trysetrate 和setrate方法Redisson是一个基于Redis的分布式Java对象和服务库。
它提供了一些方便的方法来操作和管理Redis实例。
在Redisson库中,`trySetRate`和`setRate`方法都是用来设置限流器的速率值的。
`trySetRate`方法尝试设置限流器的速率值,如果成功则返回`true`,如果限流器已经有一个速率值,则返回`false`。
该方法可以用于在多个线程中竞争设置速率值时,如果其中一个线程成功设置了速率值,其他线程将不会再设置。
```javaRLRateLimiter rateLimiter =redisson.getRateLimiter("myRateLimiter");boolean isSet = rateLimiter.trySetRate(RateType.OVERALL, 10, 1, RateIntervalUnit.SECONDS);````setRate`方法用于设置限流器的速率值,如果限流器已经有一个速率值,则会更新为新的速率值。
```javaRLRateLimiter rateLimiter =redisson.getRateLimiter("myRateLimiter");rateLimiter.setRate(RateType.OVERALL, 10, 1, RateIntervalUnit.SECONDS);```这两个方法都需要通过传入`RateType`表示要设置的速率类型,例如`RateType.OVERALL`表示设置整体速率,`RateType.PER_CLIENT`表示设置每个客户端的速率等等。
除了速率类型,还需要指定速率值和速率间隔单位。
需要注意的是,以上示例中的`redisson`对象是指从RedissonClient实例获取的,实际使用时需要根据实际情况进行初始化。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
thrift的isset方法
一、引言
在使用thrift进行开发时,我们经常会使用到isset方法。
该方法用于判断thrift生成的结构体(struct)中的字段是否被设置,从而避免在访问未设置字段时出现空指针异常。
本文将详细介绍thrift的isset方法的使用和注意事项。
二、thrift的isset方法
1. 概述
thrift是一种高效的跨语言的RPC(远程过程调用)框架,通过定义IDL(接口定义语言),生成不同语言的代码,实现不同语言间的通信。
在thrift生成的代码中,结构体(struct)是常用的数据类型,可以包含多个字段。
thrift的isset方法用于判断这些字段是否被设置。
2. 使用方法
thrift生成的结构体中,每个字段对应一个布尔型的isset变量,用于标记该字段是否被设置。
在访问字段之前,我们可以通过调用对应字段的isset方法,来判断该字段是否被设置。
例如,对于一个名为"age"的字段,我们可以使用"isset_age()"方法来判断该字段是否被设置。
3. 代码示例
以下是一个简单的thrift结构体的示例:
struct Person {
1: required string name,
2: optional i32 age,
3: optional string address
}
在使用该结构体时,我们可以通过以下方式判断字段是否被设置:Person person;
= "John";
if (person.__isset_age) {
// age字段已被设置
cout << "Age: " << person.age << endl;
} else {
// age字段未被设置
cout << "Age is not set" << endl;
}
4. 注意事项
- isset方法只能用于thrift生成的结构体中的字段,不能用于其他变量或对象。
- isset方法是自动生成的,不需要手动实现。
- 在thrift生成的代码中,每个字段的isset变量以"__isset_"开头,后面跟着字段名。
- 在访问字段之前,务必先判断该字段是否被设置,以避免访问未设置字段时出现空指针异常。
三、使用isset方法的好处
1. 避免空指针异常
在访问未设置字段时,如果没有使用isset方法进行判断,直接访问该字段,就有可能出现空指针异常。
使用isset方法可以在访问字段之前进行判断,从而避免空指针异常的发生。
2. 提高代码的健壮性
使用isset方法可以使代码更加健壮,增加容错性。
通过判断字段是否被设置,可以在代码中针对不同的情况进行相应处理,从而提高代码的可靠性和稳定性。
3. 提高代码的可读性
在代码中使用isset方法进行判断,可以使代码更加清晰易读。
通过使用语义明确的方法名,可以让其他开发人员更容易理解代码的意图和逻辑。
四、总结
thrift的isset方法是一种用于判断结构体字段是否被设置的方法。
通过使用isset方法,我们可以避免在访问未设置字段时出现空指
针异常,提高代码的健壮性和可读性。
在使用thrift进行开发时,合理使用isset方法是非常重要的。
希望本文对您理解thrift的isset方法有所帮助。