`
AILIKES
  • 浏览: 187187 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Thrift简介以及服务器和客户端的编写运行演示

阅读更多

第一部分: thrift的基本介绍以及安装
1.1 简介
         thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引 擎,以构建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 这些编程语言间无缝结合的、高效的服务。

1.2 下载
  
http://thrift.apache.org/download/  (我下载的0.5.0版本)

1.3 安装

注:在安装前请保证g++, bison 等依赖包已经安装。
sudo apt-get install libboost-dev libboost-test-dev libboost-program-options-dev libevent-dev automake libtool flex bison pkg-config g++ python-dev libssl-dev

1)tar zxf thrift-XXX.tar.gz

2)./configure
or
./configure --with-php=no --with-php_extension=no --with-python=no

在进行下一步之前,请确认是否安装python2.6-dev,若无,请安装

3)make

4)sudo make install

1.4 验证
在终端运行: thrift 
如果出现相关的提示,则表示thrift安装成功。
    
1.5 Thrift代码自动生成
在thrift-0.5.0/tutorial目录下有一个tutorial.thrif文件,为thrift类型的示例文件
在终端运行:

qifuguang@qifuguang-OptiPlex-9010:~$ cd
qifuguang@qifuguang-OptiPlex-9010:~$ thrift -gen java /opt/soft/thrift-0.5.0/tutorial/tutorial.thrift

在主文件夹下面会自动生成一个gen-java文件夹,文件夹中的tutorial目录下面生成了5个.java文件:

Thrift简介 - 黯然神伤 - DreamWill2013

 其中

Caculator.java对应tutorial.thrift文件中的

service Calculatorextends 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()
}

Constants.java对应tutorial.thrift文件中的

const i32 INT32CONSTANT =9853
const map<string,string> MAPCONSTANT ={'hello':'world','goodnight':'moon'}

InvalidOperation.java对应tutorial.thrift文件中的

exception InvalidOperation{
1: i32 what,
2:string why
}

Work.java对应tutorial.thrift文件中的

structWork{
1: i32 num1 =0,
2: i32 num2,
3:Operation op,
4: optional string comment,
}

Operation.java对应tutorial.thrift文件中的

enumOperation{
ADD =1,
SUBTRACT =2,
MULTIPLY =3,
DIVIDE =4
}



第二部分:Thrift语法
(该部分引用自:http://www.cnblogs.com/tianhuilove/archive/2011/09/05/2167669.html)

 2.1 类型

  Thrift类型系统包括预定义基本类型,用户自定义结构体,容器类型,异常和服务定义。

 2.1.1 基本类型

  • bool: 布尔值 (true or false), one byte

  • byte: 有符号字节

  • i16: 16位有符号整型

  • i32: 32位有符号整型

  • i64: 64位有符号整型

  • double: 64位浮点型

  • string: Encoding agnostic text or binary string

Note that: Thrift不支持无符号整型,因为Thrift目标语言没有无符号整型,无法转换。

 2.1.2 容器(Containers)

  Thrift容器与流行编程语言的容器类型相对应,采用Java泛型风格。它有3种可用容器类型:

  • list<t1>: 元素类型为t1的有序表,容许元素重复。(有序表ordered list不知道如何理解?排序的?c++的vector不排序)

  • set<t1>:元素类型为t1的无序表,不容许元素重复。

  • map<t1,t2>: 键类型为t1,值类型为t2的kv对,键不容许重复。

  容器中元素类型可以是除了service外的任何合法Thrift类型(包括结构体和异常)。

 2.1.3 结构体和异常(Structs and Exceptions)

  Thrift结构体在概念上类似于(similar to)C语言结构体类型--将相关属性封装在一起的简便方式。Thrift结构体将会被转换成面向对象语言的类。

  异常在语法和功能上类似于(equivalent to)结构体,差别是异常使用关键字exception而不是struct声明。但它在语义上不同于结构体:当定义一个RPC服务时,开发者可能需要声明一个远程方法抛出一个异常。

  结构体和异常的声明将在下一节介绍。

 2.1.4 服务(Services)

  服务的定义方法在语义(semantically)上等同于面向对象语言中的接口。Thrift编译器会产生执行这些接口的client和server stub。具体参见下一节。

 2.2 类型定义(Typedef)

  Thrift支持C/C++类型定义。

   typedef i32 MyInteger // a
   typedef T ReT // b

  说明:a.  末尾没有逗号。b.   struct也可以使用typedef。

 2.3 枚举(Enums)

  很多语言都有枚举,意义都一样。比如,当定义一个消息类型时,它只能是预定义的值列表中的一个,可以用枚举实现。

复制代码
enum TweetType {
    TWEET,       // (1)
   RETWEET =2, // (2)
    DM =0xa,    //(3)
   REPLY
}                //(4)

struct Tweet {
    1: required i32 userId;
    2: required string userName;
    3: required string text;
    4: optional Location loc;
    5: optional TweetType tweetType = TweetType.TWEET; // (5)
16: optional string language ="english"
}
复制代码

  说明:

  (1).  编译器默认从0开始赋值

  (2).  可以赋予某个常量某个整数

  (3).  允许常量是十六进制整数

  (4).  末尾没有分号

  (5).  给常量赋缺省值时,使用常量的全称

  注意,不同于protocal buffer,thrift不支持枚举类嵌套,枚举常量必须是32位的正整数

 2.4 注释(Comment)

  Thrift支持shell风格, C多行风格和Java/C++单行风格。

复制代码
# This is a valid comment.

/*
 * This is a multi-line comment.
 * Just like in C.
 */

// C++/Java style single-line comments work just as well.
复制代码

 2.5 名字空间(Namespace)

  Thrift中的命名空间类似于C++中的namespace和java中的package,它们提供了一种组织(隔离)代码的简便方式。名字空间也可以用于解决类型定义中的名字冲突。

  由于每种语言均有自己的命名空间定义方式(如python中有module), thrift允许开发者针对特定语言定义namespace:  

namespace cpp com.example.project  // (1)
namespace java com.example.project // (2)
namespace php com.example.project  

  (1). 转化成namespace com { namespace example { namespace project {

  (2).  转换成package com.example.project

 

 2.6 Includes

  便于管理、重用和提高模块性/组织性,我们常常分割Thrift定义在不同的文件中。包含文件搜索方式与c++一样。Thrift允许文件包含其它thrift文件,用户需要使用thrift文件名作为前缀访问被包含的对象,如:

include "tweet.thrift"// (1)
...
struct TweetSearchResult {
    1: tweet.Tweet tweet; // (2)
}

  说明:

  (1).  thrift文件名要用双引号包含,末尾没有逗号或者分号

  (2).  注意tweet前缀

 2.7 常量(Constant)

  Thrift允许定义跨语言使用的常量,复杂的类型和结构体可使用JSON形式表示。

const i32 INT_CONST =1234;    // (1)

  说明:

  (1) 分号可有可无。支持16进制。

 2.8 结构体定义(Defining Struct)

  struct是Thrift IDL中的基本组成块,由域组成,每个域有唯一整数标识符,类型,名字和可选的缺省参数组成。如定义一个类似于Twitter服务:

复制代码
struct Tweet {
    1: required i32 userId;                  // (1)
2: required string userName;             // (2)
3: required string text;
    4: optional Location loc;                // (3)
16: optional string language ="english"// (4)
}

struct Location {                            // (5)
1: required double latitude;
    2: required double longitude;
}
复制代码

 (1) 每个域有一个唯一的正整数标识符;

 (2) 每个域可标识为required或optional;

 (3) 结构体可以包含其它结构体

 (4) 域可有默认值,与required或optional无关。

 (5) Thrift文件可以定义多个结构体,并在同一文件中引用,也可加入文件限定词在其它Thrift文件中引用。

  如上所见,消息定义中的每个域都有一个唯一数字标签,这些数字标签在传输时用来确定域,一旦使用消息类型,标签不可改变。(随着项目的进展,可以要变更Thrift文件,最好不要改变原有的数字标签

  规范的struct定义中的每个域均会使用required或者 optional关键字进行标识。如果required标识的域没有赋值,Thrift将给予提示;如果optional标识的域没有赋值,该域将不会被 序列化传输;如果某个optional标识域有缺省值而用户没有新赋值,则该域的值一直为缺省值;如果某个optional标识域有缺省值或者用户已经重新赋值,而不设置它的__isset为true,也不会被序列化传输。(不被序列化传输的后果是什么?为空为零?还是默认值,下次试试)

  与services不同,结构体不支持继承。

2.9 服务定义(Defining Services)

  在流行的序列化/反序列化框架(如protocal buffer)中,Thrift是少有的提供多语言间RPC服务的框架。这是Thrift的一大特色。

  Thrift编译器会根据选择的目标语言为server产生服务接口代码,为client产生stubs。

复制代码
service Twitter {
    // 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 list are specified using the exact same syntax as
    // field lists in structs.
void ping(),                                    // (1)
bool postTweet(1:Tweet tweet);                  // (2)
    TweetSearchResult searchTweets(1:string query); // (3)

    // The 'oneway' modifier indicates that the client only makes a request and
    // does not wait for any response at all. Oneway methods MUST be void.
    oneway void zip()                               // (4)
}
复制代码
 (1) 有点乱,接口支持以逗号和分号结束;
 (2) 参数可以是基本类型和结构体;(参数是cosnt的,转换为c++语言是const&)
 (3) 返回值同参数一样;
 (4) 返回值是void,注意oneway;

Note that:参数列表的定义与结构体一样。服务支持继承。 

 

第三部分:服务器和客户端的编写与运行(java实现)

3.1 编写thrift文件

TestThrift.thrift

namespace java com.xiaomi.winwill.thrift

structBlog{
1:string topic
2:binary content
3:i64 createTime
4:string id
5:string ipAddress
6:map<string,string> props
}

service ThriftCase{
i32 testCase1(1:i32 num1,2:i32 num2,3:string num3)

list<string> testCase2(1:map<string,string> num1)

void testCase3()

void testCase4(1:list<Blog> blog)
}

3.2 生成代码 (以java语言为例)

thrift -gen java TestThrift.thrift

3.3 创建工程

在eclipse下新建一个java project,将生成的代码整个文件夹(com/xiaomi/winwill/service/*)拷贝到工程的src目录下。

3.4 实现接口

TestThrift.thrift文件中定义类一个service(ThriftCase),生成java代码之后将会变成一个接口,这些接口的作用是实现跨平台通信,但是真正的业务逻辑并未实现,所以,要做什么?怎么做?这些详细的设计应该由我们自己来实现。在工程的com.xiaomi.winwill.service包中创建一个类:Business.java,该类实现ThriftCase的Iface接口:

/**
* Business.java
* [CopyRight]
* @date 2013-7-22 下午5:27:55
*/

package com.xiaomi.winwill.service;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.thrift.TException;

import com.xiaomi.winwill.thrift.Blog;
import com.xiaomi.winwill.thrift.ThriftCase;

/**
* @author qifuguang
*/
publicclassBusinessimplementsThriftCase.Iface{

privateSet<String> keySet;
@Override
publicint testCase1(int num1,int num2,String num3)throwsTException{
System.out.println("#1: ");
if(num3.equals("+")){
System.out.println(num1+num3+num2+"="+(num1+num2));
return num1 + num2;
}
elseif(num3.equals("-")){
System.out.println(num1+num3+num2+"="+(num1-num2));
return num1 - num2;
}
elseif(num3.equals("*")){
System.out.println(num1+num3+num2+"="+(num1*num2));
return num1 * num2;
}
elseif(num3.equals("/")){
if(num2 ==0){
System.out.println("error, can not divided by zero!");
return0;
}
else{
System.out.println(num1+num3+num2+"="+(num1/num2));
return num1 / num2;
}
}
return0;
}
@Override
publicList<String> testCase2(Map<String,String> num1)throwsTException{
System.out.println("#2: ");
List<String> res =newArrayList<String>();
keySet = num1.keySet();
for(String str:keySet){
res.add(str);
}
System.out.println(res);
return res;
}
@Override
publicvoid testCase3()throwsTException{
System.out.println("#3: ");
System.out.println("Output nothing!");
}
@Override
publicvoid testCase4(List<Blog> blog)throwsTException{
System.out.println("#4: ");
for(Blog blog2 : blog){
System.out.println("id: "+blog2.getId());
System.out.println("ipAddress: "+blog2.getIpAddress());
System.out.println("createTime: "+newSimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(blog2.getCreateTime()));
System.out.println("topic: "+blog2.getTopic());
}
}
}

至于上述代码中的四个testcase方法具体实现什么功能并不重要,只是做个演示。

3.5  编写服务器代码

/**
* Server.java
* [CopyRight]
* @date 2013-7-22 下午5:26:24
*/
package com.xiaomi.winwill.service;

import java.io.IOException;
import java.net.ServerSocket;

import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportException;

import com.xiaomi.winwill.thrift.ThriftCase;

publicclassServer{
publicstaticvoid main(String[] args)throwsTTransportException,IOException{
ServerSocket socket =newServerSocket(7912);
TServerSocket serverTransport =newTServerSocket(socket);
ThriftCase.Processor processor =newThriftCase.Processor(newBusiness());
TServer server =newTSimpleServer(processor, serverTransport);
System.out.println("Running server...");
server.serve();
}
}

该类实现服务器的监听工作,创建一个TServerSocket,监听本机的7912端口。

3.6 编写客户端代码

/**
* Client.java
* [CopyRight]
* @date 2013-7-22 下午5:34:30
*/

package com.xiaomi.winwill.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;

import com.xiaomi.winwill.thrift.Blog;
import com.xiaomi.winwill.thrift.ThriftCase;


publicclassClient{
publicstaticvoid main(String[] args)throwsTException{
Map<String,String> map =newHashMap<String,String>();
List<Blog> blogs =newArrayList<Blog>();
TTransport transport =newTSocket("localhost",7912);
TProtocol protocol =newTBinaryProtocol(transport);
ThriftCase.Client client =newThriftCase.Client(protocol);
Blog blog =newBlog();
blog.createTime =System.currentTimeMillis();
blog.id ="SCUQIFUGUANG";
blog.ipAddress ="127.0.0.1";
blog.topic ="this is blog topic";
blogs.add(blog);
transport.open();
map.put("MyBlog","http://blog.163.com/scuqifuguang@126/");
System.out.println("Client calling");
client.testCase1(10,21,"+");
client.testCase2(map);
client.testCase3();

client.testCase4(blogs);

transport.close();

}
}

该类定义一个trasport,连接本机的7912端口,与服务器通讯,实现远程调用(虽然该例是在同一台电脑,不同电脑也类似)。

 

3.7 添加依赖

工程中很多地方都import了很多陌生的类,这些类包含在一下几个jar包中:

Thrift简介以及服务器和客户端的编写运行演示 - 黯然神伤 - DreamWill2013

 所以将上述几个jar包包含进工程的build path即可

3.7 工程目录结构

准备工作全部做好,看看整个工程的目录结构:

Thrift简介以及服务器和客户端的编写运行演示 - 黯然神伤 - DreamWill2013

 

3.8 运行

首先运行Server:

Thrift简介以及服务器和客户端的编写运行演示 - 黯然神伤 - DreamWill2013

 
 然后运行Client:

Thrift简介以及服务器和客户端的编写运行演示 - 黯然神伤 - DreamWill2013
 

 最后再看看Server的Console窗口:

Thrift简介以及服务器和客户端的编写运行演示 - 黯然神伤 - DreamWill2013

从运行结果可以看出,Client端已经成功地与服务器通讯,并且远程调用了服务器的四个TestCase方法。

分享到:
评论

相关推荐

    thrift_java_demo和安装包

    服务端启动一个Thrift服务器,监听特定端口,接收和响应客户端的请求;客户端则使用Thrift生成的Java客户端类,连接服务端,进行通信。 - 这个测试项目可能是为了演示如何使用Thrift进行RPC(Remote Procedure Call...

    Java Thrift demo例子

    在Java环境下,Thrift提供了强大的工具链,可以方便地构建服务端和客户端,实现快速的分布式系统开发。 在Java Thrift Demo中,我们通常会经历以下步骤: 1. 定义服务接口: 使用Thrift IDL(接口定义语言)编写...

    flume通过thrift协议收集日志-Python

    4. **编写 Python 客户端**:使用生成的 Python 代码,编写一个客户端来连接到运行在 Flume 中的 Thrift Server,并实现推送日志的功能。客户端需要连接到 Flume 的监听端口,并调用 Thrift API 发送日志。 5. **...

    Java中使用Thrift实现RPC示例代码.rar

    3. **服务端实现**:编写Java代码实现`HelloService`接口,创建一个服务器实例,监听特定端口并处理来自客户端的请求。Thrift提供了一个`Server`类,可以用来启动服务。例如: ```java public class ...

    以前整理的一点Thrift的资料

    例如,一个Java服务可以作为Thrift服务器,而Python或Go的客户端可以轻松地与其交互。 Thrift.pptx文件可能是关于Thrift的演示文稿,可能包含以下内容: - Thrift的起源和背景介绍 - Thrift的基本概念和组件 - 如何...

    thritf示例

    通过这个例子,你可以学习到Thrift的使用方法,包括编写IDL文件、生成和服务端客户端代码、以及如何在实际项目中部署和使用。这对于构建大型分布式系统或者需要多语言交互的项目来说,是非常有价值的。

    thrift-0.9.0-dev.tar.gz

    Thrift 的核心理念是通过定义一种中间语言(IDL,Interface Description Language)来描述服务接口,然后自动生成各种编程语言的客户端和服务器端代码,使得不同语言之间可以进行高效、可靠的通信。在Thrift IDL中,...

    maven-thrift-client

    它允许开发者定义服务接口和服务数据类型,然后自动生成多种编程语言的客户端和服务器端代码,以实现高效的、轻量级的通信。Maven 是 Java 开发中最常用的构建工具,负责管理项目的依赖、构建过程和生命周期。当这两...

    开源项目-thrift-iterator-go.zip

    它通过IDL来定义服务接口和数据类型,然后自动生成相应的客户端和服务器端代码。 这个项目特别之处在于,它允许你在不使用IDL的情况下处理Thrift消息。这意味着你可以解析和构建Thrift消息流,即使你没有原始的IDL...

    thriftpy2:Apache Thrift的纯Python方法

    $ pip install cython thriftpy2代码演示ThriftPy使使用Thrift编写服务器/客户端代码变得超级容易。 让我们来看看这个简单的乒乓球服务演示。 我们需要一个“ pingpong.thrift”文件: service PingPong { string ...

    thriftSoft.rar

    例如,通过Thrift IDL,你可以声明一个服务,其中包含一系列的函数调用,然后在C#、Java、Python等不同的语言环境中实现这个服务的客户端和服务器端。 在C#中使用Thrift,开发者首先需要编写.IDL文件,定义服务和...

    javaToPython.zip

    同时,Python服务需要启动一个Thrift服务器,监听指定端口,等待Java客户端的连接。 6. **Java与Python的数据交换**: Thrift支持多种数据类型,包括基本类型、结构体、枚举等,使得Java和Python之间可以方便地...

    thrift-mina:Thrift on Apache Mina, 利用Apache Mina重构Thrift的Transport和数据传输协议

    3. **示例或测试**:可能包括演示如何使用thrift-mina的样例服务和客户端,以及相关的单元测试,帮助理解如何在实际项目中集成和使用这个库。 4. **文档**:README文件或其他文档,解释了项目的安装、配置和使用...

    php链接HIVE的例子代码

    3. **编写PHP代码**:创建一个PHP脚本,使用Thrift客户端库连接到Hive Server2。在代码中,你需要指定Hive服务器的地址、端口,以及SASL的认证信息。然后,你可以创建一个Hive服务的实例,调用其提供的方法执行HQL...

    rpc.rar_RPC windows linux

    9. **多语言支持**:RPC框架应提供跨平台和跨语言的支持,使不同编程语言编写的客户端和服务端能顺利通信。 压缩包中的“rpc”文件可能是源代码、配置文件或示例应用,用于展示如何在Windows和Linux之间实现RPC通信...

    节俭演示

    这里提到了`thrift-go`,这暗示我们这个演示是围绕Thrift框架进行的,Thrift是一种跨语言的服务开发工具,由Facebook开发,它允许定义数据类型和服务接口,然后自动生成在多种编程语言中的客户端和服务器端代码,以...

    IceServerClient.rar

    在这种场景下,`Ice`(即Thrift的前身)作为一种高效的分布式对象框架,提供了强大的接口定义语言和运行时系统,用于构建跨语言、跨平台的分布式应用。而`Qt`则是一个广泛使用的C++图形用户界面库,能帮助开发者创建...

    基于Java实现的RPC项目源码+项目说明.zip

    按照grpc的方式,编写接口HelloService,以及里面的消息体HelloRequest和HelloResponse,客户端和服务器都使用这同一套接口 ## 第二步:编写RPC协议 RpcRequest和RpcResponse都是RPC协议,RPC协议包括header和body...

    RPC简介-第1部分

    - 示例代码:通过一个简单的RPC客户端/服务器示例,演示了如何在C++环境下编写RPC程序,可能使用了VC6、VC7.0、VC7.1、VC8.0等编译器,并在Windows XP、Win2003、Win2K等操作系统上运行。 - STL(Standard Template ...

    精通并发与netty视频教程(2018)视频教程

    44_NIO网络客户端编写详解 45_深入探索Java字符集编解码 46_字符集编解码全方位解析 47_Netty服务器与客户端编码模式回顾及源码分析准备 48_Netty与NIO系统总结及NIO与Netty之间的关联关系分析 49_零拷贝深入剖析及...

Global site tag (gtag.js) - Google Analytics