THRIFT 开发教程
thrift正常的调用过程
自动化thrift的代码示例_server端
thrift的使用过程改进
1 使用thrift工具生成客户端和服务器端代码框架
2
开发人员编写自己的业务代码
3
开发人员用‘thrift生成的代码’+’自己编写 的业务代码’组装成真正的服务
由于thrift设计充分采用了分层思想,这使得我们有可能把上面第二个 环节给省略掉,而采用自动化的方式来完成,这样就比使用thrift生成的静 态代码更能给开发人员带来简便、灵活性。改进后的使用过程如下:
// 第三步: 使用自动Client实例,调用具体的远端服务(用户自己编写的业务代码) CommonArgs tmpCommonArgs = new CommonArgs(); tmpCommonArgs.addOneValue("uid", 10); tmpCommonArgs.addOneValue("test", "test123"); ArrayList tmpList = (ArrayList) client.sendRequest("retrieve", tmpCommonArgs);
tmpAutoThriftGenerator.generateAutoThrift("D:/资料/thrift", "firstTest.thrift"); AutoProcessorGenerator tmpAutoProcessorGenerator = new AutoProcessorGenerator(); TBaseProcessor tmpProcessor = tmpAutoProcessorGenerator.generate("UserStorage", handler, tmpThriftServicesParser);
Thrift之代码生成器Compiler原理及源码详细解析1
Thrift之代码⽣成器Compiler原理及源码详细解析1欢迎⼤家相互交流,共同提⾼技术。
⼜很久没有写博客了,最近忙着研究GlusterFS,本来周末打算写⼏篇博客的,但是由于调试GlusterFS的⼀些新增功能就⽤了整整的⼀天,还有⼀天就陪⽼婆⼤⼈逛街去了!今晚浏览完微博发现时间还早就来博客⼀篇,本篇博客内容主要是前⼀段时间研究的Thrift的代码⽣成器的源码详细分析,没有具体分析语法解析,因为是⼯具字段⽣成的代码,⼈是没有办法阅读的----到处都是跳转表!由于Thrift⽀持N多种语⾔,但是⽣成代码原理都差不多,我主要分析了C++相关代码⽣成。
关于Thrift的使⽤及原理、代码⽹上基本上都有,代码的注释很好,基本上都是英⽂注释。
下⾯就是我之前分析写的⽂档,希望对学习使⽤代码⽣成代码的爱好者有⼀定帮助。
Thrift之代码⽣成器Compiler原理及源码详细解析1这个功能是⼀个单独的⼯具程序,它会独⽴的⽣成⼀个可执⾏⽂件。
第⼀节类关系图本节主要展⽰了这个部分的整体类图,然后对这个类图做了简要的说明,有了这个类图让我在阅读这个部分源代码时不会找不到⽅向,让我更加清楚这个部分中的类是怎样协同⼯作的,类关系图如下所⽰:注意:实线代表继承关系;⽽虚线代表依赖关系。
由类关系图可以看出Compiler功能模块主要分为两个部分,⼀个是图的右边展⽰了各种语⾔代码⽣成的类。
它们的共同基类都是t_generator类,但是⾯向对象的语⾔并不是直接从它继承,⽽是⼜把⾯向对象的共同特性提取出来⽤⼀个类来实现,这个类就是t_oop_generator,其他⾯向对象语⾔的⽣成类都是从这个类继承。
总基类的实现是依赖于左边的t_program类,这个类表⽰⼀个程序代码需要的所有特征和要素。
左边部分就是解决⼀个程序需要拥有的数据类型和函数,根据接⼝定义语⾔(IDL)解析和⽣成相应的数据和函数等。
左边部分就显⽰thrift定义的中间语⾔(IDL)能够⽀持的数据类型,t_type类是所有数据类型类的基类。
thrift协议
thrift协议Thrift协议。
Thrift是一个跨语言的远程服务调用框架,最初由Facebook开发,用于解决不同语言之间的服务调用和数据传输问题。
Thrift协议作为Thrift框架的核心部分,扮演着非常重要的角色。
本文将介绍Thrift协议的基本原理、使用方法以及其在实际开发中的应用。
Thrift协议的基本原理是通过定义数据类型和接口规范,实现不同语言之间的数据传输和服务调用。
Thrift支持多种数据类型,包括基本数据类型(如整型、浮点型、布尔型等)和复杂数据类型(如结构体、集合、映射等),并且可以根据需要自定义数据类型。
在定义数据类型的同时,还需要定义接口规范,包括服务的名称、方法的参数和返回值等信息。
通过这些定义,Thrift可以自动生成不同语言的代码,实现数据的序列化和反序列化,以及远程服务的调用。
在使用Thrift协议时,首先需要定义数据类型和接口规范,然后通过Thrift提供的代码生成工具生成对应的代码。
生成的代码包括客户端和服务端的代码,客户端代码用于调用远程服务,服务端代码用于实现远程服务。
在客户端代码中,Thrift提供了一套通信协议和传输协议,用于实现数据的序列化和反序列化,以及数据的传输。
在服务端代码中,需要实现定义的接口规范,并提供相应的服务逻辑。
在实际开发中,Thrift协议可以应用于各种跨语言的远程服务调用场景。
例如,一个基于Java开发的服务需要被C++客户端调用,可以使用Thrift协议实现跨语言的服务调用。
在这种场景下,只需要定义好数据类型和接口规范,然后生成对应的代码,就可以实现Java服务和C++客户端之间的数据传输和服务调用。
总的来说,Thrift协议作为Thrift框架的核心部分,通过定义数据类型和接口规范,实现了跨语言的数据传输和服务调用。
在实际开发中,Thrift协议可以帮助开发人员解决不同语言之间的服务调用和数据传输问题,极大地提高了开发效率和系统的可扩展性。
Windows下Thrift环境搭建与示例
Windows下Thrift环境搭建与示例目录WINDOWS下THRIFT环境搭建与示例 (1)目录 (2)1.引言 (3)2.环境搭建 (4)1.1.JAVA环境 (4)1.2.T HRIFT环境 (4)3.THRIFT的基本概念 (4)1.3.数据类型 (4)1.4.服务端编码基本步骤: (5)1.5.客户端编码基本步骤: (5)1.6.数据传输协议 (5)4.实例演示 (6)4.1.THRIFT生成代码 (6)4.1.1.创建thrift文件 (6)4.1.2.编译thrift文件 (6)4.2.代码实现 (7)4.2.1.实现服务端接口 (7)4.2.2.TSimpleServer服务端 (8)4.2.3.客户端 (9)4.3.依赖库设置 (12)4.4.运行 (12)1.引言本文档介绍windows环境下thrift的环境搭建与开发。
IDE为Eclipse,语言为Java。
Thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。
它结合了功能强大的软件堆栈和代码生成引擎,以构建在C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 等等编程语言间无缝结合的、高效的服务。
官网地址:参考:/soa/rpc/thrift-sample//jnb/jnbJun2009.html/thrift/static/files/thrift-20070401.pdf/search-engine/thrift-for-windows//search-engine/thrift-rpc/2.环境搭建1.1.java环境下载JDK和ANT,并且配置环境变量。
测试是否配置成功,如下:下载安装Eclipse,用于java程序的开发。
1.2.Thrift环境下载Thrift: /download解压thrift-0.9.1.tar.gz,复制到C盘。
thrift 开发教程
1 编写thrift文件(如aa.thrift)namespace java 189.uc.thriftnamespace cppthrift.vdbnamespace rbthrift.vdbnamespace perlthrift.vdbnamespace csharpthrift.vdbnamespace jsthrift.vdbnamespace stthrift.vdbnamespace pythrift.vdbnamespace php thriftserviceUCThriftService{string ucOperator(1:string actionType, 2:string uid, 3:string data),}2 生成java文件thrift-0.6.0.exe -r --gen java uc.thriftthrift-0.6.0.exe -r --gen java uc.thriftthrift-0.6.0.exe -r --gen phpuc.thriftthrift-0.6.0.exe -r --gen pyuc.thrift可以生成php,py等等的3 服务端编写1)实现UCThriftService.Ifacepublic class UCThriftServiceImpl implements UCThriftService.Iface {public static Logger logger = Logger.getLogger(UCThriftServiceImpl.class);@Overridepublic String ucOperator(String actionType, String suid, String data)throws TException {System.out.println("test");}}2)运行的main编写public class UCServiceServer {private static Logger logger = Logger.getLogger(UCServiceServer.class);public static void main(String... args) throws Exception {//这个是用properties编写的,可以自行决定String server = PropertiesUtil.getValue("tserver.properties","ucserver.nio","hahs"); if ("nio".equalsIgnoreCase(server)) {startNIO();} if ("hahs".equalsIgnoreCase(server)) {startHAHS();} else {start();}}private static void start() throws TTransportException {String address = PropertiesUtil.getValue("tserver.properties","ucserver.address","0.0.0.0");int port = Integer.parseInt(PropertiesUtil.getValue("tserver.properties","ucserver.port","5555")); intclientTimeout =Integer.parseInt(PropertiesUtil.getValue("tserver.properties","ucserver.clientTimeout","30000")); intminWorkerThreads =Integer.parseInt(PropertiesUtil.getValue("tserver.properties","ucserver.minWorkerThreads","25")); intmaxWorkerThreads =Integer.parseInt(PropertiesUtil.getValue("tserver.properties","ucserver.maxWorkerThreads","25")); String protocol = PropertiesUtil.getValue("tserver.properties","ucserver.protocol","binary"); TServerSocket socket = new TServerSocket(new InetSocketAddress(address,port), clientTimeout);UCThriftService.Processor process = new UCThriftService.Processor(UCThriftServiceImpl.instance());TThreadPoolServer.Argsarg = new TThreadPoolServer.Args(socket);if("compact".equalsIgnoreCase(protocol)){arg.protocolFactory(new TCompactProtocol.Factory());}else if("binary".equalsIgnoreCase(protocol)){arg.protocolFactory(new TBinaryProtocol.Factory());}else{arg.protocolFactory(new TBinaryProtocol.Factory());}arg.transportFactory(new TFramedTransport.Factory());arg.maxWorkerThreads(maxWorkerThreads);arg.minWorkerThreads(minWorkerThreads);// arg.processor(process);arg.processorFactory(new TProcessorFactory(process));TServer server = new TThreadPoolServer(arg);Logger.getLogger(UCServiceServer.class).info(UCServiceServer.class.getSimpleName() + " Listen at " + port);while(true){try {server.serve();} catch (Exception e) {logger.error(e.getMessage(),e);server.stop();Logger.getLogger(UCServiceServer.class).info(UCServiceServer.class.getSimpleName() + " Reload");server = new TThreadPoolServer(arg);}}}private static void startNIO() throws TTransportException {String address = PropertiesUtil.getValue("tserver.properties","ucserver.address","0.0.0.0");int port = Integer.parseInt(PropertiesUtil.getValue("tserver.properties","ucserver.port","5555")); intclientTimeout =Integer.parseInt(PropertiesUtil.getValue("tserver.properties","ucserver.clientTimeout","30000")); String protocol = PropertiesUtil.getValue("tserver.properties","ucserver.protocol","binary"); TNonblockingServerSocket socket = new TNonblockingServerSocket(new InetSocketAddress(address, port), clientTimeout);UCThriftService.Processor process = new UCThriftService.Processor( UCThriftServiceImpl.instance());TNonblockingServer.Argsarg = new TNonblockingServer.Args(socket);if("compact".equalsIgnoreCase(protocol)){arg.protocolFactory(new TCompactProtocol.Factory());}else if("binary".equalsIgnoreCase(protocol)){arg.protocolFactory(new TBinaryProtocol.Factory());}else{arg.protocolFactory(new TBinaryProtocol.Factory());}arg.transportFactory(new TFramedTransport.Factory());// arg.processor(process);arg.processorFactory(new TProcessorFactory(process));TServer server = new TNonblockingServer(arg);Logger.getLogger(UCServiceServer.class).info("NIO " + UCServiceServer.class.getSimpleName() + " Listen at "+ port);while(true){try {server.serve();} catch (Exception e) {server.stop();Logger.getLogger(UCServiceServer.class).info("NIO " + UCServiceServer.class.getSimpleName() + " Reload");server = new TNonblockingServer(arg);}}}private static void startHAHS() throws TTransportException {String address = PropertiesUtil.getValue("tserver.properties","ucserver.address","0.0.0.0");int port = Integer.parseInt(PropertiesUtil.getValue("tserver.properties","ucserver.port","5555")); intclientTimeout =Integer.parseInt(PropertiesUtil.getValue("tserver.properties","ucserver.clientTimeout","30000")); intminWorkerThreads =Integer.parseInt(PropertiesUtil.getValue("tserver.properties","ucserver.minWorkerThreads","25")); String protocol = PropertiesUtil.getValue("tserver.properties","ucserver.protocol","binary");TNonblockingServerSocket socket = new TNonblockingServerSocket(new InetSocketAddress(address, port), clientTimeout);UCThriftService.Processor process = new UCThriftService.Processor(UCThriftServiceImpl.instance());THsHaServer.Argsarg = new THsHaServer.Args(socket);if("compact".equalsIgnoreCase(protocol)){arg.protocolFactory(new TCompactProtocol.Factory());}else if("binary".equalsIgnoreCase(protocol)){arg.protocolFactory(new TBinaryProtocol.Factory());}else{arg.protocolFactory(new TBinaryProtocol.Factory());}arg.transportFactory(new TFramedTransport.Factory());arg.workerThreads(minWorkerThreads);// arg.processor(process);arg.processorFactory(new TProcessorFactory(process));TServer server = new THsHaServer(arg);Logger.getLogger(UCServiceServer.class).info("HAHS " + UCServiceServer.class.getSimpleName() + " Listen at "+ port);while(true){try {server.serve();} catch (Exception e) {logger.error(e.getMessage(),e);server.stop();Logger.getLogger(UCServiceServer.class).info("HAHS " + UCServiceServer.class.getSimpleName() + " Reload");server = new TNonblockingServer(arg);}}}}4 客户端编写public void newThread() throws TException {String address = "0.0.0.0";int port = 5555;intclientTimeout = 30000;TTransport transport = new TFramedTransport(new TSocket(address, port, clientTimeout));TProtocol protocol = new TBinaryProtocol(transport);UCThriftService.Client client = new UCThriftService.Client(protocol); transport.open();try {long bt = System.currentTimeMillis();System.out.println(URLDecoder.decode(client.ucOperator("get", "29", "")));} catch (TApplicationException e) {System.out.println(e.getMessage() + " " + e.getType());}transport.close();}5运行先运行ucserverclient连接可在控制台看到输出说明:client连服务端有几个要注意的地方:1 服务器的ip和端口2 服务端和客户端用的transport 和协议一定要一样比如:如果服务端用的TFrameTransport那客户端也要用TFrameTransport 如果服务端用的TBinaryProtocol,那客户端也要用TBinaryProtocol否则会出一个好像是TTransportException的一个异常。
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⽂件夹找到.。
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的类。
java thrift用法
java thrift用法Java Thrift用法Thrift是一种高效、容易使用且跨语言的远程服务框架,它可以帮助开发者通过定义一个简单的服务接口描述语言(IDL)来生成不同语言间的代码。
以下是Java Thrift的一些常见用法:安装Thrift安装Thrift需要先下载并安装Thrift的二进制文件。
你可以从官方网站(定义Thrift IDLThrift使用IDL来定义服务接口和数据结构。
在一个以.thrift 为后缀的文件中,你可以定义多个服务和数据类型。
生成Java代码通过运行Thrift编译器,可以将Thrift IDL文件转换为Java代码文件。
使用以下命令行实现:thrift --gen java your_thrift_这将生成一个gen-java目录,其中包含了将在Java中使用的自动生成的代码。
实现服务接口在生成的Java代码中,你可以找到用于实现Thrift服务接口的接口和类。
你需要实现服务接口并编写具体的业务逻辑。
启动Thrift服务通过实例化Thrift创建的服务接口的具体实现类,使用TProcessor和TServerSocket创建一个服务处理器。
然后,你可以创建一个服务器并启动它。
创建客户端创建一个Thrift客户端来调用Thrift服务。
客户端需要指定服务器的主机和端口,并使用TTransport和TProtocol与服务器建立连接。
调用服务方法使用生成的Thrift客户端代码,你可以直接调用定义在IDL中的服务方法。
这些方法的参数和返回类型将在生成的客户端代码中定义。
总结Thrift是一个强大且灵活的远程服务框架,可以帮助开发者轻松地构建跨语言的服务。
通过定义Thrift IDL,并使用Thrift编译器生成Java代码,可以快速地实现服务接口和客户端。
通过Thrift,你可以更方便地构建可扩展和高效的分布式应用程序。
处理异常在使用Thrift调用远程服务时,可能会出现一些异常情况,如网络连接异常或服务端处理错误。
c++thrift用法
c++thrift用法C++ Thrift 是 Apache Thrift 的 C++ 版本实现,它是一种跨语言的远程服务调用框架,可以用于构建高效的跨语言服务。
下面我会从多个角度介绍 C++ Thrift 的用法。
1. 安装和配置:要使用 C++ Thrift,首先需要安装 Thrift 编译器和 C++ Thrift 库。
安装 Thrift 编译器后,可以使用 .thrift 文件定义接口和数据类型,然后使用编译器生成对应的 C++ 代码。
在 C++项目中,需要将生成的代码添加到项目中,并链接 Thrift 库。
2. 定义接口和数据类型:在 .thrift 文件中,可以定义接口和数据类型。
接口定义了服务的方法,数据类型定义了服务的参数和返回值的结构。
例如: thrift.namespace cpp YourNamespace.service YourService {。
i32 YourMethod(1: i32 param1, 2: string param2)。
}。
3. 生成代码:使用 Thrift 编译器生成 C++ 代码。
在命令行中执行类似以下命令:thrift --gen cpp YourThriftFile.thrift.这将生成 C++ 代码文件,包括接口定义和数据类型的序列化和反序列化代码。
4. 实现服务:在生成的代码中,实现接口定义的方法。
这些方法将处理远程调用请求,并返回结果。
你需要编写实际的业务逻辑来实现这些方法。
5. 客户端调用:在客户端代码中,使用生成的客户端代码来调用远程服务。
客户端代码提供了远程服务的代理,可以方便地调用远程方法并处理返回结果。
6. 异常处理:在 C++ Thrift 中,可以处理远程调用过程中的异常。
在服务端和客户端都需要处理可能出现的异常情况,以确保系统的稳定性和可靠性。
总之,C++ Thrift 提供了一种方便快捷的方式来实现跨语言的远程服务调用。
Thrift自动生成代码处理层的实现做详细分析
之前对Thrift自动生成代码的实现细节做了详细的分析,下面进行处理层的实现做详细分析了!会利用到自动代码生成的知识。
这部分是协议层和用户提供的服务实现之间的纽带,定义了调用服务实现的接口框架,真正实现某种服务接口是通过上一章介绍的代码生成工具生成的代码。
本章将介绍这个框架的基本原理,然后通过生成的一个实例来具体介绍怎样完成一次完整的服务,这个可能涉及到下面章节的一些知识,对于这些知识不详细分析其功能,只是介绍它在其中起什么作用。
选择的实例是Facebook内部用这个框架实现的一个分布式日志收集系统scribe。
下面是这部分相关类的类关系图:从上图中可以看出TProcessor是这个部分的顶层基类,其他之类基本上都是通过Thrift代码生成工具生成的,只有少数是为了扩展一些功能而直接写代码实现,如PeekProcessor类就增加了一些对原始数据处理的功能。
scribeProcessor和FacebookServiceProcessor类就是用代码生成器根据IDL文件生成的,也是我们后面需要分析的一个实例。
第一节服务接口调用框架分析这个基本的框架包括三个类,一个就是抽象类TProcessor,负责调用用户定义的服务接口,从一个接口读入数据,写入一个输出接口。
一个最主要的函数定义如下:1virtual bool process(boost::shared_ptr<protocol::TProtocol> in,23 boost::shared_ptr<protocol::TProtocol> out, void* connec tionContext) = 0;这个函数是一个纯虚函数,所以继承这个类的子类都必须实现这个函数,这个函数就是最主要的数据传输功能。
第二个类就是负责处理TProcessor类产生的事件的类TProcessorEventHandler,主要定义了一些当某事件发生时的处理函数,例如梦芭莎优惠券当读取参数之前可以做一些处理功能。
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关键字声明。
pythonthrift教程
pythonthrift教程本⽂主要简单记录rpc框架thrift的使⽤,详细可查第⼀步:安装thrift命令⾏输⼊ brew install thrift (此⽅法仅适⽤于mac,其他安装⽅法查看教程)第⼆步:编写⼀个.thrift⽂件⾸先这个.thrift⽂件是什么作⽤呢?其实这个⽂件主要⽤类c语⾔的写法定义⼀些常量、结构、类和⽅法。
然后为什么要定义这个.thrift⽂件呢?我们知道thrift RPC框架是可以⽀持20多中语⾔的如python、java、go、php、C++等,我们需要定义这个.thrift⽂件,然后通过thrift程序把它转换成你需要语⾔的格式,也就是我们第三步要做的。
这⾥我们写个rpc.thirft⽂件⽰例:namespace py rpcnamespace java rpcnamespace go rpc//上⾯内容可以省略//定义常量⽰例const string HELLO_WORLD = "world"//定义结构体⽰例struct Resp{1: i32 Code=0,2: string Msg="",}//定义接⼝⽰例service HelloWorld {void ping(), //接⼝⽅法Resp sayHello(), /接⼝的返回值为Resp结构体形式string sayMsg(1:string msg)}第三步:把根据我们定义的.thrift⽂件,thrift⾃动⽣成代码命令⾏输⼊thrift --gen <language> <Thrift filename>例如我们是python语⾔,然后⽂件名为rpc.thrift所以我们输⼊命令thrift --gen py pc.thrift在你输⼊完命令刷新后,会⾃动出现gen-py⽬录,我们可以将它理解为我们RPC程序的脚⼿架第四步:有了脚⼿架后,我们就可以编写客户端和服务端了客户端⽂件⽰例 client.py:import syssys.path.append('./gen-py')from rpc import HelloWorldfrom rpc.ttypes import *from rpc.constants import *from thrift import Thriftfrom thrift.transport import TSocketfrom thrift.transport import TTransportfrom thrift.protocol import TBinaryProtocoltry:# Make sockettransport = TSocket.TSocket('127.0.0.1', 30303)# Buffering is critical. Raw sockets are very slowtransport = TTransport.TBufferedTransport(transport)# Wrap in a protocolprotocol = TBinaryProtocol.TBinaryProtocol(transport)# Create a client to use the protocol encoderclient = HelloWorld.Client(protocol)# Connect!transport.open()client.ping()print("ping()")msg = client.sayHello()print(msg, type(msg)) # 这⾥发送的是之前⽂件中定义的常量HELLO_WORDmsg = client.sayMsg(HELLO_WORLD)print(msg)transport.close()except Thrift.TException as tx:print("%s" % (tx.message))然后编写服务端程序service.py:import syssys.path.append('./gen-py')from rpc import HelloWorldfrom rpc.ttypes import *from thrift.transport import TSocketfrom thrift.transport import TTransportfrom thrift.protocol import TBinaryProtocolfrom thrift.server import TServerimport socketclass HelloWorldHandler:def__init__(self):self.log = {}def ping(self):print("ping()")def sayHello(self):print("sayHello()") # 这⾥我返回的是之前定义的Resp结构体return Resp(1, "hahah")def sayMsg(self, msg):print(1212)return msghandler = HelloWorldHandler()processor = HelloWorld.Processor(handler)transport = TSocket.TServerSocket('127.0.0.1', 30303)tfactory = TTransport.TBufferedTransportFactory()pfactory = TBinaryProtocol.TBinaryProtocolFactory()server = TServer.TSimpleServer(processor, transport, tfactory, pfactory) print("Starting python server...")server.serve()print("done!")这两个⽂件放在gen-py⽬录下第五步:先启动service端,然后再启动client端然后你查看控制台就可以看到,客户端与服务端之间的通信输出了如:service端:/usr/local/bin/python3.7 /Users/bytedance/PycharmProjects/untitled5_django/rpc/service.py Starting python server...ping()sayHello()1212client端输出:/usr/local/bin/python3.7 /Users/bytedance/PycharmProjects/untitled5_django/rpc/client.py ping()Resp(Code=1, Msg='hahah') <class'rpc.ttypes.Resp'>worldProcess finished with exit code 0。
C小白的thrift环境搭建
C⼩⽩的thrift环境搭建公司有个通讯是⽤的 thrift ,thrift 是个什么都东西,可以类⽐ webservice 吧,⽐ webservice ⾼效些,不管是啥,搞他!先在 mac 上搞本地开发环境⽹上⼀搜貌似依赖 boost、libeventboost 是 c/c++ std 的拓展,⼀些 list、vector 等等啥的,好像还有些⽐ std 更⾼级的功能,旁边搞c 的同事说太重了,他⼀般不⽤,不管了,下下来libevent 是 c/c++ 的⽹络通讯框架,类似java 下的 nio ?也下下来按⽹上的步骤安装 boost,发现依赖⾼版本的 bison(2.6,系统⾃带的是2.4),这个 bison 是⼲啥的?“语法分析器⽣成器” ,是类似语法检查的?就是说标准的 c/c++ gcc 来检查,拓展的 boost 的语法由 bison 来检查?我先这样理解吧libevent 依赖 openssl,直接编译会报错 "<openssl/bio.h> not found"⼀、安装bisonwget /gnu/bison/bison-2.6.4.tar.gztar -zxvf bison-2.6.4.tar.gzcd bison-2.6.4./configure./configure && make -j $(getconf _NPROCESSORS_ONLN) && make install# -j 意思好像是⼀共是⼏核⼏线程,加速 make 的速度的bison -V# 如果不⾏,就退出 Terminal 再启动试试⼆、安装 boosttar -zxvf boost_1_66_0.tar.gz./bootstrap.sh —prefix=PATH_TO_BOOSTsudo ./b2 threading=multi address-model=64 variant=release stage install三、安装openssl#先⽤ brew 安装# ---------------------------------------------------------------------------------------------------brew install openssl#安装到了 /usr/local/Cellar/openssl/1.0.2n/bin 下直接 openssl version 肯定是不⾏的sudo mv /usr/bin/openssl /usr/bin/openssl_oldsudo mv /usr/local/Cellar/openssl/1.0.2n/bin/openssl /usr/bin/openssl# macOS Sierra 下 /usr/bin 是没有权限修改的,需要进⼊安全模式# 1、重启 2、开机按下 commond +r 3、进⼊terminal 敲⼊ csrutil disable# 但是 mv 了也还是不⾏,不能安装 libevent 估计是依赖的静态类库或者动态类库,没拷贝,只拷贝了⼆进制可执⾏程序brew link openssl# 是不是把 lib 也拷贝过去了呢,好像也不⾏,算了换源码安装# ---------------------------------------------------------------------------------------------------tar -zxvf openssl-1.0.2l.tarcd openssl-1.0.2lsudo ./config --prefix=/usr/local/opensslmakemake install# 在安装 libevent 的时候还是不⾏,缺少依赖的 openssl 的类库 "<openssl/bio.h> not found"# 后来拷贝了头⽂件,使得编译通过cp -R /usr/local/Cellar/openssl/1.0.2n/include/ /Users/carl/Downloads/libevent-2.1.8-stable四、安装 libeventcd libevent-2.0.21-stable./configure --prefix=/usr/localmake cleanmake && make install五、安装 thriftcd thrift-0.9.3./bootstrap.sh./configure --prefix=/usr/local/ --disable-static --with-boost=/usr/local --with-libevent=/usr/local --without-python --without-csharp --without-ruby --without-perl --without-php --without-haskell --without-erlangmakemake install完成 thrift 安装thrift --version可以看到其版本号码编写 thrift 的 demo_server、demo_client 的 hello world 程序时,却发现在mac 系统下并没有其没有⽣产对应的类库编译不报错,但运⾏ demo_server 时报错了错误是dyld: Symbol not found: _GENERAL_NAME_freeReferenced from: /usr/local/lib/libthrift-0.9.3.dylibExpected in: flat namespacein /usr/local/lib/libthrift-0.9.3.dylibAbort trap: 6这个搞半天,⽐如在 thrift configure 之后,make 之前加上export CXXFLAGS="-std=c++11"#直接导致 thrift ⽆法⽣成了发现貌似是 Mac 的 gcc 是⽤的 llvm + clang ,这两货应该就是 linux 下的 gcc 的 mac 版本,就是说不是普通的 gcc 了,貌似上述问题都是由于 mac 导致的,不管了,先在centos 虚拟机下⾯配置,如果可⾏的话,在把 gcc 给换了centos 下的 thrift 安装步骤⼤同⼩异只是默认 centos 6.5 下 cmake 都没有在编译 demo 程序时,安装都 cmake 版本还要求⽐较⾼,⾼版本的 cmake 还需要⾼版本的 gcc⼀路升级吧# 先 gcc 升级到最新版本,是 4.8,找到⼀个 yum 的升级⽅法cd /etc/yum.repos.dwget /tru/devtools-2/devtools-2.repoyum install devtoolset-2-gccyum install devtoolset-2-binutilsyum install devtoolset-2-gcc-gfortranyum install devtoolset-2-gcc-c++source /opt/rh/devtoolset-2/enablecmake 3.11 安装./bootstrap --prefix=/usrmakemake install终于可以运⾏ thrift 的 demo 了。
Thrift安装编译指南
Thrift安装编译指南前⾔:thrift的版本问题⽐较⿇烦,⾼版本的在c++上需要c++ 11的⽀持,⽽低版本则可能在go的⽀持上有问题,测试发现thrift 9.0以上需要c++ 11,⽽thrift 8.0则在go的⽀持上可能会存在问题。
使⽤的发⾏版本是centos 6.5,gcc 4.4.7。
最终选择使⽤thrift-0.8.0来编译安装。
⼀. 编译安装wget /dist/thrift/0.8.0/thrift-0.8.0.tar.gztar -zxvf thrift-0.8.0.tar.gzcd thrift-0.11.0./configure #这⼀步配置可以选择⽀持的语⾔,如python,c++,go等。
可以./configure --help来查看可配置项。
如./configure --without-gomake && make install注意:在执⾏完configure后,会显⽰实际上⽀持的库,⽐如thrift 0.11.0Building C (GLib) Library .... : noBuilding C# (Mono) Library ... : noBuilding C++ Library ......... : yesBuilding D Library ........... : noBuilding Dart Library ........ : noBuilding dotnetcore Library .. : noBuilding Erlang Library ...... : noBuilding Go Library .......... : noBuilding Haskell Library ..... : noBuilding Haxe Library ........ : noBuilding Java Library ........ : noBuilding Lua Library ......... : noBuilding NodeJS Library ...... : noBuilding Perl Library ........ : noBuilding PHP Library ......... : noBuilding Plugin Support ...... : noBuilding Python Library ...... : yesBuilding Py3 Library ......... : yesBuilding Ruby Library ........ : noBuilding Rust Library ........ : no如果编译没问题,那么就可以查看⼀下版本thrift -version,如果能显⽰,那么就ok。
使用thrift做c++,java和python的相互调用
使用thrift做c++,java和python的相互调用linux上安装thrift见/blog/1102535thrift做为跨语言调用的计划有高效,支持语言较多,成熟等优点;代码侵入较强是其弱点。
下面记录以C++做服务器,C++,java和python做客户端的示例,这个和本人现在工作环境吻合,用法多线程长衔接的socket来建立高效分布式系统的跨语言调用平台。
圆满的是目前版本(0.7.0)的C语言还不支持Compact协议,导致在现在的环境中nginx c mole调用thrift要用法binary协议。
thrift开发团队似乎对C语言不太感冒。
1.定义l文件acser.thrift suct User{ 1: string uid, 2: string , 3: bool us, 4: i16 uage, service UserService{ void a(1: User u), User get(1: string uid), 2.生成c++,java和python代码框架 thrift -r --gen p user.thrift thrift -r --gen java user.thrift thrift -r --gen py user.thrift 这时生成子名目gen-cpp,gen-java,gen-py3.生成C++服务端代码 cp gen-cpp/UserService_server.skeleton.cpp UserServer.cpp 修改UserServer.cpp ilude "UserService.h" include config.h //include proto/TBinaryProtocol.h include protocol/TCompactProtocol.h include server/TSimpleServer.h include transport/TServerSocket.h includetransport/TBufferTransports.h includeconcurrency/ThreadManager.h includeconcurrency/PosixThreadFactory.h includeserver/TThreadPoolServer.h include server/TThreadServer.h using namespace ::apache::thrift; usingnamespace ::apache::thrift::protocol; usingnamespace ::apache::thrift::transport; usingnamespace ::apache::thrift::server; usingnamespace ::apache::thrift::concurrency; using第1页共5页。
thrift.exe用法
thrift.exe用法Thrift是一款编程框架,可以用于进行跨语言的远程过程调用(RPC)通信。
它包括一组代码生成工具、库以及各种支持文件,用于自动生成代码,使得在不同编程语言中进行的程序之间可以互相调用。
在Thrift框架中,thrift.exe是一个非常重要的工具,本文将详细介绍thrift.exe的用法,以帮助初学者更好地掌握Thrift框架的使用。
1. thrift.exe的作用thrift.exe是一款命令行工具,其主要作用是用于将Thrift的IDL文件生成对应的可编译源代码文件。
IDL文件定义了所有Thrift服务,包括服务名、服务方法、参数以及返回值等。
使用thrift.exe可以将IDL文件转换成各种语言对应的源代码文件,如C++、Java、Python等。
2. 安装thrift.exe安装完成后,需要将thrift.exe所在的路径添加到系统环境变量中,这样就可以在任意目录下使用thrift.exe命令。
3. thrift.exe的常用参数使用thrift.exe时可以指定不同的参数来生成不同语言的代码文件。
下面是一些常用的参数及其解释:- -r: 指定IDL文件的目录,可以用于同时处理多个IDL文件及其依赖文件。
- -out: 指定代码文件的输出目录。
- -v: 输出详细的调试信息。
- -o: 生成对应语言的代码文件。
以下命令可以将IDL文件生成Python语言的代码文件,并输出到指定目录中:```thrift.exe -r [IDL文件所在目录] -out [输出目录] -gen py```4. thrift.exe的使用示例下面将以一个简单的示例来演示thrift.exe的使用。
我们需要创建一个简单的IDL文件test.thrift,如下所示:```namespace py testservice TestService {string hello(1: string name)}```namespace指定了代码文件的包名,service定义了一个名为TestService的服务,包含一个名为hello的方法。
throttle函数
throttle函数throttle函数是一种用于控制函数执行频率的技术。
在编程中,有时我们需要确保一些函数在一定时间范围内只能被调用一次,或者以一定的频率被调用。
throttle函数可以帮助我们实现这一目标,它可以在特定时间窗口内忽略额外的函数调用,从而限制函数执行频率。
一个基本的throttle函数的实现通常包含以下几个关键步骤:1.在函数内部定义一个变量来存储时间戳,用于跟踪上次函数调用的时间。
2.在每次函数调用时,检查当前时间与上次函数调用的时间间隔是否超过了指定的时间窗口。
如果超过了时间窗口,就执行函数并更新时间戳;否则,忽略该次函数调用。
3.在步骤2中,如果函数被执行了,那么通常需要将执行的结果返回出去;否则,如果函数调用被忽略了,可以选择返回上一次有效调用的结果,或者返回空值。
下面是一个示例的throttle函数实现:```javascriptfunction throttle(func, delay)let lastResult;return function(...args)const context = this;lastResult = func.apply(context, args);}, delay);}return lastResult;};```throttle函数的应用场景非常广泛。
比如,当用户频繁操作一些按钮时,我们可以使用throttle函数限制按钮点击的频率,避免误操作或者多次提交。
又或者,当用户在输入框中连续输入时,我们可以使用throttle函数限制触发后端请求的频率,减少无效或重复的请求。
总之,throttle函数是一种非常实用的函数节流技术,可以帮助我们更好地控制函数的执行频率,提升性能和用户体验。
Thrift下java服务器与客户端开发指南
THRIFTJava服服务器及客户端开发指南修订历史记录2010-05-07 用Thrift开发Java服务器及客户端程序张晴相关联系人正文目录1 创建THRIFT 文件 (4)1.1 编写TEST J AVA .THRIFT (4)1.2 运行THRIFT编译器,生成项目源文件 (4)2 创建JAVA 服务器 (5)2.1 编写S OMETHING I MPL .JAVA (5)2.2 创建S ERVER.JAVA (5)3 创建JAVA 客户端 (7)4 编译及运行 (8)4.1 编译 (8)4.2 运行 (8)1 创建Thrift 文件Thrift 文件与编程语言无关,用于定义数据类型和服务接口,然后生成用来构建和服务RPC 客户器所需的全部代码。
1.1 编写testJava.thrift#!/usr/local/bin/thrift --gen javanamespace java Testservice Something {i32 ping()}1.2 运行thrift 编译器,生成项目源文件在linux 命令行下输入:Thrift - gen java testJava.thrift生成的源文件在./gen-java/ 目录下。
2创建Java服服务器进入./gen-java目录,确保系统的CLASSPATH设置正确。
libthrift.jar,,slf4j-api和slf4j-simple 这几个包都需要包含在CLASSPATH里。
2.1 编写SomethingImpl.javapackage Test;import org.apache.thrift.TException;class SomethingImpl implements Something.Iface {public SomethingImpl() {}public int ping() throws TException {System.out.println( "Recieve ping from client..." );return 0;}}2.2 创建Server.javapackage Test;import java.io.IOException;import org.apache.thrift.protocol.TBinaryProtocol;import org.apache.thrift.protocol.TBinaryProtocol.Factory;import org.apache.thrift.server.TServer;import org.apache.thrift.server.TThreadPoolServer;import org.apache.thrift.transport.TServerSocket;import org.apache.thrift.transport.TTransportException;public class Server {private void start() {try {TServerSocket serverTransport = new TServerSocket(7911);Something.Processor processor = new Something.Processor(new SomethingImpl());Factory protFactory = new TBinaryProtocol.Factory(true, true);TServer server = new TThreadPoolServer(processor, serverTransport, protFactory);System.out.println("Starting server on port 7911 ...");server.serve();} catch (TTransportException e) { e.printStackTrace();} catch (Exception e) { e.printStackTrace();}}public static void main(String args[]) {Server srv = new Server(); srv.start();}}3创建Java客户端创建Client.javapackage Test;import java.io.IOException;import org.apache.thrift.*;import org.apache.thrift.protocol.*;import org.apache.thrift.transport.*;public class Client {public static void main(String [] args) {try {TTransport transport = new TSocket("localhost", 7911); TProtocol protocol= new TBinaryProtocol(transport); Something.Client client = newSomething.Client(protocol); transport.open();System.out.println("Client calls ping()"); client.ping();transport.close();} catch (TException x) {x.printStackTrace();}}}4 编译及运行4.1 编译在linux命令行下输入:javac *.java,生成客户端与服务器端的class文件。
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之TProtocol类体系原理及源码详细解析之二进制协议类TBinaryPro。。。
Thrift之TProtocol类体系原理及源码详细解析之⼆进制协议类TBinaryPro。
欢迎⼤家相互交流,共同提⾼技术。
这个协议是Thrift⽀持的默认⼆进制协议,它以⼆进制的格式写所有的数据,基本上直接发送原始数据。
因为它直接从TVirtualProtocol类继承,⽽且是⼀个模板类。
它的模板参数就是⼀个封装具体传输发送的类,这个类才是真正实现数据传输的。
这个类的定义上⼀节举例已经出现过了就不在列出来了。
下⾯我就结合scribe的Log函数执⾏的具体过程来分析使⽤这个协议所执⾏的功能,看看⼆进制协议是怎样⼯作的。
RPC调⽤使⽤到协议部分主要是在发送函数相关信息到服务器和接收服务器返回结果。
现在我就结合Log函数的实现代码具体分析。
⾸先看看Log函数的发送相关信息函数send_log(在⽂件scribe.cpp):1void scribeClient::send_Log(const std::vector<LogEntry> & messages)23 {45 int32_t cseqid = 0;67 oprot_->writeMessageBegin("Log", ::apache::thrift::protocol::T_CALL, cseqid);//写⼊函数调⽤消息89 scribe_Log_pargs args;1011 args.messages = &messages;1213 args.write(oprot_);//调⽤参数类⾃⼰的写⼊函数写⼊参数到服务器1415 oprot_->writeMessageEnd();//写⼊消息调⽤写⼊1617 oprot_->getTransport()->writeEnd();//结束传输层的写⼊1819 oprot_->getTransport()->flush();//刷新传输流,让写⼊马上执⾏,因为RPC调⽤需要马上得到结果2021 }从上⾯代码可以看出:⾸先调⽤具体⼀个协议的writeMessageBegin函数,当然这个我们分析的是⼆进制协议,那就看看⼆进制协议这个函数的实现,代码如下:1 template <class Transport_>23 uint32_t TBinaryProtocolT<Transport_>::writeMessageBegin(const std::string& name,45const TMessageType messageType, const int32_t seqid) {67if (this->strict_write_) {//判断是否需要强制写⼊版本号89 int32_t version = (VERSION_1) | ((int32_t)messageType);//本版号是协议号和消息类型的与结果1011 uint32_t wsize = 0;//记录写⼊的长度1213 wsize += writeI32(version);//写版本号1415 wsize += writeString(name);//写消息名称,这就是函数名称Log1617 wsize += writeI32(seqid);//写调⽤序列号1819return wsize;//返回写⼊的长度2021 } else {2223 uint32_t wsize = 0;2425 wsize += writeString(name);2627 wsize += writeByte((int8_t)messageType);2829 wsize += writeI32(seqid);3031return wsize;3233 }3435 }根据上⾯代码和注释可以看出,根据是否需要写⼊协议版本号写⼊的内有所差别,写⼊协议号的⽬的是可以坚持客户端和服务器端是否使⽤相同的协议来传输的数据,保证数据格式的正确性。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1编写thrift文件(如aa.thrift)namespace java 189.uc.thriftnamespace cpp thrift.vdbnamespace rb thrift.vdbnamespace perl thrift.vdbnamespace csharp thrift.vdbnamespace js thrift.vdbnamespace st thrift.vdbnamespace py thrift.vdbnamespace php thriftservice UCThriftService{string ucOperator(1:string actionType,2:string uid,3:string data),}2生成java文件thrift-0.6.0.exe-r--gen java uc.thriftthrift-0.6.0.exe-r--gen java uc.thriftthrift-0.6.0.exe-r--gen php uc.thriftthrift-0.6.0.exe-r--gen py uc.thrift可以生成php,py等等的3服务端编写1)实现UCThriftService.Ifacepublic class UCThriftServiceImpl implements UCThriftService.Iface{public static Logger logger=Logger.getLogger(UCThriftServiceImpl.class);@Overridepublic String ucOperator(String actionType,String suid,String data)throws TException{System.out.println("test");}}2)运行的main编写public class UCServiceServer{private static Logger logger=Logger.getLogger(UCServiceServer.class);public static void main(String...args)throws Exception{//这个是用properties编写的,可以自行决定String server=PropertiesUtil.getValue("tserver.properties","ucserver.nio","hahs"); if("nio".equalsIgnoreCase(server)){startNIO();}if("hahs".equalsIgnoreCase(server)){startHAHS();}else{start();}}private static void start()throws TTransportException{String address=PropertiesUtil.getValue("tserver.properties","ucserver.address","0.0.0.0");int port=Integer.parseInt(PropertiesUtil.getValue("tserver.properties","ucserver.port","5555"));int clientTimeout=Integer.parseInt(PropertiesUtil.getValue("tserver.properties","ucserver.clientTimeout","30000")); int minWorkerThreads=Integer.parseInt(PropertiesUtil.getValue("tserver.properties","ucserver.minWorkerThreads","25")); int maxWorkerThreads=Integer.parseInt(PropertiesUtil.getValue("tserver.properties","ucserver.maxWorkerThreads","25")); String protocol=PropertiesUtil.getValue("tserver.properties","ucserver.protocol","binary"); TServerSocket socket=new TServerSocket(new InetSocketAddress(address,port),clientTimeout);UCThriftService.Processor process=new UCThriftService.Processor( UCThriftServiceImpl.instance());TThreadPoolServer.Args arg=new TThreadPoolServer.Args(socket);if("compact".equalsIgnoreCase(protocol)){arg.protocolFactory(new TCompactProtocol.Factory());}else if("binary".equalsIgnoreCase(protocol)){arg.protocolFactory(new TBinaryProtocol.Factory());}else{arg.protocolFactory(new TBinaryProtocol.Factory());}arg.transportFactory(new TFramedTransport.Factory());arg.maxWorkerThreads(maxWorkerThreads);arg.minWorkerThreads(minWorkerThreads);//arg.processor(process);arg.processorFactory(new TProcessorFactory(process));TServer server=new TThreadPoolServer(arg);Logger.getLogger(UCServiceServer.class).info(UCServiceServer.class.getSimpleName()+"Listen at"+port);while(true){try{server.serve();}catch(Exception e){logger.error(e.getMessage(),e);server.stop();Logger.getLogger(UCServiceServer.class).info(UCServiceServer.class.getSimpleName()+"Reload");server=new TThreadPoolServer(arg);}}}private static void startNIO()throws TTransportException{String address=PropertiesUtil.getValue("tserver.properties","ucserver.address","0.0.0.0");int port=Integer.parseInt(PropertiesUtil.getValue("tserver.properties","ucserver.port","5555")); int clientTimeout=Integer.parseInt(PropertiesUtil.getValue("tserver.properties","ucserver.clientTimeout","30000")); String protocol=PropertiesUtil.getValue("tserver.properties","ucserver.protocol","binary"); TNonblockingServerSocket socket=new TNonblockingServerSocket(new InetSocketAddress(address,port),clientTimeout);UCThriftService.Processor process=new UCThriftService.Processor( UCThriftServiceImpl.instance());TNonblockingServer.Args arg=new TNonblockingServer.Args(socket);if("compact".equalsIgnoreCase(protocol)){arg.protocolFactory(new TCompactProtocol.Factory());}else if("binary".equalsIgnoreCase(protocol)){arg.protocolFactory(new TBinaryProtocol.Factory());}else{arg.protocolFactory(new TBinaryProtocol.Factory());}arg.transportFactory(new TFramedTransport.Factory());//arg.processor(process);arg.processorFactory(new TProcessorFactory(process));TServer server=new TNonblockingServer(arg);Logger.getLogger(UCServiceServer.class).info("NIO"+UCServiceServer.class.getSimpleName()+"Listen at"+port);while(true){try{server.serve();}catch(Exception e){server.stop();Logger.getLogger(UCServiceServer.class).info("NIO"+UCServiceServer.class.getSimpleName()+"Reload");server=new TNonblockingServer(arg);}}}private static void startHAHS()throws TTransportException{String address=PropertiesUtil.getValue("tserver.properties","ucserver.address","0.0.0.0");int port=Integer.parseInt(PropertiesUtil.getValue("tserver.properties","ucserver.port","5555")); int clientTimeout=Integer.parseInt(PropertiesUtil.getValue("tserver.properties","ucserver.clientTimeout","30000")); int minWorkerThreads=Integer.parseInt(PropertiesUtil.getValue("tserver.properties","ucserver.minWorkerThreads","25")); String protocol=PropertiesUtil.getValue("tserver.properties","ucserver.protocol","binary");TNonblockingServerSocket socket=new TNonblockingServerSocket(new InetSocketAddress(address,port),clientTimeout);UCThriftService.Processor process=new UCThriftService.Processor( UCThriftServiceImpl.instance());THsHaServer.Args arg=new THsHaServer.Args(socket);if("compact".equalsIgnoreCase(protocol)){arg.protocolFactory(new TCompactProtocol.Factory());}else if("binary".equalsIgnoreCase(protocol)){arg.protocolFactory(new TBinaryProtocol.Factory());}else{arg.protocolFactory(new TBinaryProtocol.Factory());}arg.transportFactory(new TFramedTransport.Factory());arg.workerThreads(minWorkerThreads);//arg.processor(process);arg.processorFactory(new TProcessorFactory(process));TServer server=new THsHaServer(arg);Logger.getLogger(UCServiceServer.class).info("HAHS"+UCServiceServer.class.getSimpleName()+"Listen at"+port);while(true){try{server.serve();}catch(Exception e){logger.error(e.getMessage(),e);server.stop();Logger.getLogger(UCServiceServer.class).info("HAHS"+UCServiceServer.class.getSimpleName()+"Reload");server=new TNonblockingServer(arg);}}}}4客户端编写public void newThread()throws TException{String address="0.0.0.0";int port=5555;int clientTimeout=30000;TTransport transport=new TFramedTransport(new TSocket(address,port, clientTimeout));TProtocol protocol=new TBinaryProtocol(transport);UCThriftService.Client client=new UCThriftService.Client(protocol); transport.open();try{long bt=System.currentTimeMillis();System.out.println(URLDecoder.decode(client.ucOperator("get","29","")));}catch(TApplicationException e){System.out.println(e.getMessage()+""+e.getType());}transport.close();}5运行先运行ucserverclient连接可在控制台看到输出说明:client连服务端有几个要注意的地方:1服务器的ip和端口2服务端和客户端用的transport和协议一定要一样比如:如果服务端用的TFrameTransport那客户端也要用TFrameTransport 如果服务端用的TBinaryProtocol,那客户端也要用TBinaryProtocol否则会出一个好像是TTransportException的一个异常。