热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Apachethrif安装以及使用详解

----------------------1.简单介绍Thrift是Facebook的一个开源项目,主要是一个跨语言的服务开发框架。它有一个代码生成器来对它所定义的IDL定义文件自动生成服务代码框架。用户只要在其之前进行二次开发就行,对于底层的RPC通讯等都是透明的。目前它支持

----------------------

1. 简单介绍

Thrift是Facebook的一个开源项目,主要是一个跨语言的服务开发框架。它有一个代码生成器来对它所定义的IDL定义文件自动生成服务代码框架。用户只要在其之前进行二次开发就行,对于底层的RPC通讯等都是透明的。目前它支持的语言有C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk, and OCaml.

2. 下载与安装

可以在http://incubator.apache.org/thrift/download/去下载它的最新版本,目前最新版本是0.5.0。另外你也可以check出它的svn,方法如下:

svn co http://svn.apache.org/repos/asf/thrift/trunk thrift

cd thrift

在它的jira中看到,它的0.6版本也很快就会出来了。

我的本本是debian 6.0,如果用ubuntu的兄弟安装方法也是一样的

tar -zxvf thrift-0.5.0.tar.gz
cd thrift-0.5.0
./configure
make
sudo make install
 

这时thrift的代码生成器和一些库文件就生成好了。

你可以用如下命令看一下thrift的版本信息

thrift -version
 

3. 一个简单的例子

在thrift源代码目录有一个叫tutorial的目录,进行其中后运行thrift命令生成相应的服务代码:

$ thrift -r --gen cpp tutorial.thrift // -r对其中include的文件也生成服务代码 -gen是生成服务代码的语言
 

运行完之后会在当前目录看到一个gen-cpp目录,其中就是thrfit命令生成的代码

这时你cd到tutorial/cpp目录,运行make,生成相应的CppServer与CppClient程式。

这时你可以用./CppServer运行服务端,让其监听一个特定的端口

这时你可以用./CppClient运行客户端程式,让其去连接服务端,调用其所对应的服务。默认调用后会输出如下信息:

lemo@debian:~/Workspace/Facebook/Thrift/thrift-0.5.0/tutorial/cpp$ ./CppServer
Starting the server...
ping()
add(1,1)
calculate(1,{4,1,0})
calculate(1,{2,15,10})
getStruct(1)
 

如果你的终端中也出现了如上的信息,恭喜你,运行成功了。如果在运行CppServer的时候找不到动态库,看看你是不是运行了make install,如果运行了,再运行一下sudo ldconfig试试。再用ldd CppServer看一下它有没有找到相应的动态库了。

4. 例子分析 4.1 Thrift IDL的分析

这边有两个IDL文件,内容如下:

shared.thrift
---------------
**
 * This Thrift file can be included by other Thrift files that want to share
 * these definitions.
 */
namespace cpp shared
namespace java shared
namespace perl shared
// 这里定义了一个结构体,没有定义方法,对应于生成的代码在gen-cpp中的shared_types.h中,其中有一个class叫SharedStruct,
// 有没有看到其中有两个方法叫read和write,这就是用来对其进行序列化与把序列化的方法.
// 对了,其中的i32是Thrift IDL中定义的变量类型,对应于c++语言中的int32_t
struct SharedStruct {
  1: i32 key
  2: string value
}
// 这里定义的一个服务,它语义上类似于面向对象中的定义一个接口,thrift的编译器会对其产生一套实现其接口的客户端与服务端方法
// 服务的一般定义格式如下
// service 
//  ()
// [ throws ()]
//   ...
// }
service SharedService {
  SharedStruct getStruct(1: i32 key)
}
tutorial.thrift
----------------
/**
 * Thrift files can reference other Thrift files to include common struct
 * and service definitions. These are found using the current path, or by
 * searching relative to any paths specified with the -I compiler flag.
 *
 * Included objects are accessed using the name of the .thrift file as a
 * prefix. i.e. shared.SharedObject
 */
 // 这个IDL包含了另一个IDL,也就是说另一个IDL中的对象与服务对其时可见的
include "shared.thrift"
/**
 * Thrift files can namespace, package, or prefix their output in various
 * target languages.
 */
 // 这里定义了一些语言的namespace空间
namespace cpp tutorial
namespace java tutorial
namespace php tutorial
namespace perl tutorial
/**
 * Thrift lets you do typedefs to get pretty names for your types. Standard
 * C style here.
 */
 // 自定义类型
typedef i32 MyInteger
/**
 * Thrift also lets you define constants for use across languages. Complex
 * types and structs are specified using JSON notation.
 */
 // 定义一些变量
const i32 INT32CONSTANT = 9853
const map MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}
/**
 * You can define enums, which are just 32 bit integers. Values are optional
 * and start at 1 if not supplied, C style again.
 */
 // 定义枚举类型
enum Operation {
  ADD = 1,
  SUBTRACT = 2,
  MULTIPLY = 3,
  DIVIDE = 4
}
/**
 * Structs are the basic complex data structures. They are comprised of fields
 * which each have an integer identifier, a type, a symbolic name, and an
 * optional default value.
 *
 * Fields can be declared "optional", which ensures they will not be included
 * in the serialized output if they aren't set.  Note that this requires some
 * manual management in some languages.
 */
struct Work {
  1: i32 num1 = 0,
  2: i32 num2,
  3: Operation op,
  4: optional string comment, //这里的optional字段类型表示如果这个字段的值没有被赋值,它就不会被序列化输出
}
/**
 * Structs can also be exceptions, if they are nasty.
 */
 // 这里定义了一些异常
exception InvalidOperation {
  1: i32 what,
  2: string why
}
/**
 * Ahh, now onto the cool part, defining a service. Services just need a name
 * and can optionally inherit from another service using the extends keyword.
 */
 // 这里是定义服务,它继承了shared的服务
service Calculator extends shared.SharedService {
  /**
   * A method definition looks like C code. It has a return type, arguments,
   * and optionally a list of exceptions that it may throw. Note that argument
   * lists and exception lists are specified using the exact same syntax as
   * field lists in struct or exception definitions.
   */
   void ping(),
   i32 add(1:i32 num1, 2:i32 num2),
   i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),
   /**
    * This method has a oneway modifier. That means the client only makes
    * a request and does not listen for any response at all. Oneway methods
    * must be void.
    */
   oneway void zip()
}
 

4.2 服务端与客户端代码的分析    4.2.1 c++服务端

   在tutorial/cpp目录中的CppServer.cpp是它的服务代码,主要分成两部分,

   一部分是main方法用于做一些初始化与服务的启动,第二部分对于IDL中定义的接口的实现

   int main(int argc, char **argv) {
// 定义了RPC的协议工厂,这里使用了二进制协议,你不可以使用别的协议,如JSON,Compact等
shared_ptr protocolFactory(new TBinaryProtocolFactory());
// 这里生成用户实现的CalculatorHandler服务,再把其帮定到一个Processor上去,它主要用于处理协议的输入与输出流
shared_ptr handler(new CalculatorHandler());
shared_ptr processor(new CalculatorProcessor(handler));
// 生成一个传输通道,这里使用了Socket方式
shared_ptr serverTransport(new TServerSocket(9090));
// 生成一个传输工厂,主要用于把上面的transport转换成一个新的应用层传输通道
shared_ptr transportFactory(new TBufferedTransportFactory());
// 生成一个简单的服务端,这是一个单线程的服务端
TSimpleServer server(processor,
                      serverTransport,
                      transportFactory,
                      protocolFactory);
// 你也可以生成一个多线程的服务端,就是对其加入线程池。但它现在还不支持进程池,但可能会在0.7版本中进行支持。
 /**
  * Or you could do one of these
 shared_ptr threadManager =
   ThreadManager::newSimpleThreadManager(workerCount);
 shared_ptr threadFactory =
   shared_ptr(new PosixThreadFactory());
 threadManager->threadFactory(threadFactory);
 threadManager->start();
 TThreadPoolServer server(processor,
                          serverTransport,
                          transportFactory,
                          protocolFactory,
                          threadManager);
 TThreadedServer server(processor,
                        serverTransport,
                        transportFactory,
                        protocolFactory);
 */
 printf("Starting the server.../n");
 server.serve();   // 启动服务
 printf("done./n");
 return 0;
}
 

另一部分如下:

// 这一部分主要是实现接口类,用于提供给相应的服务使用。
class CalculatorHandler : public CalculatorIf {
public:
 CalculatorHandler() {}
 void ping() {
   printf("ping()/n");
 }
 int32_t add(const int32_t n1, const int32_t n2) {
   ...
 }
 int32_t calculate(const int32_t logid, const Work &work) {
 ...
 }
 void getStruct(SharedStruct &ret, const int32_t logid) {
 ...
 }
 void zip() {
   printf("zip()/n");
 }
protected:
 map log;
};
 

4.2.2 c++客户端

int main(int argc, char** argv) {
 // 生成一个Socket连接到服务端
 shared_ptr socket(new TSocket("localhost", 9090));
 // 对Socket通道加入缓冲功能
 shared_ptr transport(new TBufferedTransport(socket));
 // 生成相应的二进制协议,这个要和服务端一致,不然会出现协议版本不对的错误
 shared_ptr protocol(new TBinaryProtocol(transport));
 // 生成客户端的服务对象
 CalculatorClient client(protocol);
 try {
   transport->open(); // 加开服务
   // 调用事先定义好的服务接口
   client.ping();
   printf("ping()/n");
   int32_t sum = client.add(1,1);
   printf("1+1=%d/n", sum);
   Work work;
   work.op = Operation::DIVIDE;
   work.num1 = 1;
   work.num2 = 0;
   try {
     int32_t quotient = client.calculate(1, work);
     printf("Whoa? We can divide by zero!/n");
   } catch (InvalidOperation &io) {
     printf("InvalidOperation: %s/n", io.why.c_str());
   }
   work.op = Operation::SUBTRACT;
   work.num1 = 15;
   work.num2 = 10;
   int32_t diff = client.calculate(1, work);
   printf("15-10=%d/n", diff);
   // Note that C++ uses return by reference for complex types to avoid
   // costly copy construction
   SharedStruct ss;
   client.getStruct(ss, 1);
   printf("Check log: %s/n", ss.value.c_str());
   // 关闭服务
   transport->close();
 } catch (TException &tx) {
   printf("ERROR: %s/n", tx.what());
 }
}
 

4.2.3 其它代码的实现

在tutorial目录中有其它代码的例子,如erl,java,python,perl,ruby等。


推荐阅读
  • 精选10款Python框架助力并行与分布式机器学习
    随着神经网络模型的不断深化和复杂化,训练这些模型变得愈发具有挑战性,不仅需要处理大量的权重,还必须克服内存限制等问题。本文将介绍10款优秀的Python框架,帮助开发者高效地实现分布式和并行化的深度学习模型训练。 ... [详细]
  • Windows环境下详细教程:如何搭建Git服务
    Windows环境下详细教程:如何搭建Git服务 ... [详细]
  • 本文总结了一次针对大厂Java研发岗位的面试经历,探讨了面试中常见的问题及其背后的原因,并分享了一些实用的面试准备资料。 ... [详细]
  • MyBatisCodeHelperPro 2.9.3 最新在线免费激活方法
    MyBatisCodeHelperPro 2.9.3 是一款强大的代码生成工具,适用于多种开发环境。本文将介绍如何在线免费激活该工具,帮助开发者提高工作效率。 ... [详细]
  • Hyperledger Fabric 1.4 节点 SDK 快速入门指南
    本文将详细介绍如何利用 Hyperledger Fabric 1.4 的 Node.js SDK 开发应用程序。通过最新版本的 Fabric Node.js SDK,开发者可以更高效地构建和部署基于区块链的应用,实现数据的安全共享和交易处理。文章将涵盖环境配置、SDK 安装、示例代码以及常见问题的解决方法,帮助读者快速上手并掌握核心功能。 ... [详细]
  • 本文详细介绍了在CentOS 6.5 64位系统上使用阿里云ECS服务器搭建LAMP环境的具体步骤。首先,通过PuTTY工具实现远程连接至服务器。接着,检查当前系统的磁盘空间使用情况,确保有足够的空间进行后续操作,可使用 `df` 命令进行查看。此外,文章还涵盖了安装和配置Apache、MySQL和PHP的相关步骤,以及常见问题的解决方法,帮助用户顺利完成LAMP环境的搭建。 ... [详细]
  • Apache Hadoop HDFS QJournalProtocol 中 getJournalCTime 方法的应用与代码实例分析 ... [详细]
  • 第六章:枚举类型与switch结构的应用分析
    第六章深入探讨了枚举类型与 `switch` 结构在编程中的应用。枚举类型(`enum`)是一种将一组相关常量组织在一起的数据类型,广泛存在于多种编程语言中。例如,在 Cocoa 框架中,处理文本对齐时常用 `NSTextAlignment` 枚举来表示不同的对齐方式。通过结合 `switch` 结构,可以更清晰、高效地实现基于枚举值的逻辑分支,提高代码的可读性和维护性。 ... [详细]
  • REST与RPC:选择哪种API架构风格?
    在探讨REST与RPC这两种API架构风格的选择时,本文首先介绍了RPC(远程过程调用)的概念。RPC允许客户端通过网络调用远程服务器上的函数或方法,从而实现分布式系统的功能调用。相比之下,REST(Representational State Transfer)则基于资源的交互模型,通过HTTP协议进行数据传输和操作。本文将详细分析两种架构风格的特点、适用场景及其优缺点,帮助开发者根据具体需求做出合适的选择。 ... [详细]
  • 解决Cookie中无法存储特殊字符的问题及优化方案
    在实现购物车功能时,需要将JSON格式的数据存储到Cookie中,但由于JSON数据中包含特殊字符(如双引号),导致无法直接存储。本文提出了一种解决方案,通过编码和解码技术对特殊字符进行处理,确保数据能够安全存储并正确读取。此外,还介绍了优化Cookie存储性能的方法,以提高用户体验和系统效率。 ... [详细]
  • HBase客户端Table类中getRpcTimeout方法的应用与编程实例解析 ... [详细]
  • 作为140字符的开创者,Twitter看似简单却异常复杂。其简洁之处在于仅用140个字符就能实现信息的高效传播,甚至在多次全球性事件中超越传统媒体的速度。然而,为了支持2亿用户的高效使用,其背后的技术架构和系统设计则极为复杂,涉及高并发处理、数据存储和实时传输等多个技术挑战。 ... [详细]
  • 深入解析Tomcat:开发者的实用指南
    深入解析Tomcat:开发者的实用指南 ... [详细]
  • NoSQL数据库,即非关系型数据库,有时也被称作Not Only SQL,是一种区别于传统关系型数据库的管理系统。这类数据库设计用于处理大规模、高并发的数据存储与查询需求,特别适用于需要快速读写大量非结构化或半结构化数据的应用场景。NoSQL数据库通过牺牲部分一致性来换取更高的可扩展性和性能,支持分布式部署,能够有效应对互联网时代的海量数据挑战。 ... [详细]
  • Java中将Map及其他对象高效转换为JSON格式的方法探讨 ... [详细]
author-avatar
别样青年别样范儿bo
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有