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

Thrift基础(一)Hello World

 
阅读更多

昨天写的 thrift 基础的例子


1、thrift 是什么:

thrift 是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 这些编程语言间无缝结合的、高效的服务。thrift 最初由 facebook 开发,07年四月开放源码,08年5月进入apache孵化器。(这段话是百度的
现在的官方网站:http://thrift.apache.org/ 最新版0.9.2


2、开发简单的例子
实际上thrift就是生成一个各个语言下都能通用的Entity类,Service接口和通讯协议。
首先要到官网上下载thrift的可执行程序,用于生成上边写的Entity和Service接口。
下载地址:http://thrift.apache.org/download
下载 Thrift compiler 即可,我是 windows 直接改名称为 thrift.exe 放到了系统的 windows 目录下。所以到时候命令行直接执行命令即可(懒得配单独的环境变量啊)。

 

开发:
使用的是Java
先是maven的配置

<dependency>
  <groupId>org.apache.thrift</groupId>
  <artifactId>libthrift</artifactId>
  <version>0.9.2</version>
</dependency>

 
PS:话说才发现 storm 里也有 thrift 的包不过包名怎么都改成了 org.apache.thrift7 了。

首先是Entity类和Service接口:
随便找个文本文件管理器比如Notepad++或者SublimeText之类的写一个文件,文件名helloworld.thrift
内容:

namespace java com.nanxiaoqiang.test.thrift.demo1// java下的包路径
// 生成方式 bash:thrift -r -gen java helloworld.thrift
struct Helloworld{
    1:i32 id;
    2:string name;
}

service HelloworldService{
    bool insertHelloworld(1:Helloworld helloworld),
    bool removeHelloworld(1:i32 id),
    Helloworld getHelloworld(1:i32 id)
}

 
然后命令行下 thrift -r -gen java helloworld.thrift 即可生成两个文件:Helloworld.javaHelloworldService.java

 

PS:关于这个IDL类型的文件到底应当怎么写,下边的是参考文档:

http://thrift.apache.org/docs/types 官方文档

http://wiki.apache.org/thrift/ Wiki百科

http://www.cnblogs.com/tianhuilove/archive/2011/09/05/2167669.html    tianhuilove的博客


接着是具体Service的实现,模拟了一个类似于CURD的方法内容

package com.nanxiaoqiang.test.thrift.demo1;

import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.thrift.TException;

import com.nanxiaoqiang.test.thrift.demo1.HelloworldService.Iface;

/**
 * Handler 数据处理接口
 *
 * @author nanxiaoqiang
 *
 * @version 0.1
 *
 * @since 2015年3月21日
 *
 */
public class HelloworldServiceImpl implements Iface {

    private static Logger logger = LogManager
            .getLogger(HelloworldServiceImpl.class.getName());

    ConcurrentHashMap<Integer, Helloworld> map = new ConcurrentHashMap<>();

    public HelloworldServiceImpl() {
        Helloworld h = new Helloworld();
        h.setId(0);
        h.setName("NULL");
        map.put(h.getId(), h);
        logger.info("constructor HelloworldServiceImpl:add new Helloworld,now map size is "
                + map.size());
    }

    @Override
    public boolean insertHelloworld(Helloworld helloworld) throws TException {
        if (helloworld == null || helloworld.getId() == 0) {
            logger.info("error object of Helloworld. map size is " + map.size());
            return false;
        } else {
            logger.info(ToStringBuilder.reflectionToString(helloworld,
                    ToStringStyle.MULTI_LINE_STYLE));
            map.put(helloworld.getId(), helloworld);
            logger.info("insert complete. map size is " + map.size());
            return true;
        }
    }

    @Override
    public boolean removeHelloworld(int id) throws TException {
        if (id == 0) {
            logger.info("can not remove with id 0. map size is " + map.size());
            return false;
        } else if (map.containsKey(id)) {
            logger.info(ToStringBuilder.reflectionToString(map.get(id),
                    ToStringStyle.MULTI_LINE_STYLE));
            map.remove(id);
            logger.info("removed complete with id " + id + ". map size is "
                    + map.size());
            return true;
        } else {
            logger.info("can not find object with id " + id + ". map size is "
                    + map.size());
            return false;
        }
    }

    @Override
    public Helloworld getHelloworld(int id) throws TException {
        if (map.containsKey(id)) {
            Helloworld h = map.get(id);
            logger.info(ToStringBuilder.reflectionToString(h,
                    ToStringStyle.MULTI_LINE_STYLE));
            return h;
        } else {
            logger.info("can not find object with id " + id + ". map size is "
                    + map.size());
            return null;
        }
    }

}

 

接着是 Server 端:

package com.nanxiaoqiang.test.thrift.demo1;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportException;

/**
 * 一个基本的Thrift的例子,Server 服务模型,线程安全
 * 
 * @author nanxiaoqiang
 * 
 * @version 0.1
 * 
 * @since 2015年3月21日
 *
 */
public class Server {
	private static Logger logger = LogManager.getLogger(Server.class.getName());

	public static final int SERVER_PORT = 9999;

	public Server() {
	}

	public void startServer() {
		logger.info("准备启动TProcessor");
		TProcessor tprocessor = new HelloworldService.Processor<HelloworldService.Iface>(
				new HelloworldServiceImpl());

		// 简单的单线程服务模型,一般用于测试
		try {
			// 支持的服务模型
			// TSimpleServer – 简单的单线程服务模型,常用于测试
			// TThreadedServer - 多线程服务模型,使用阻塞式IO,每个请求创建一个线程。
			// TThreadPoolServer – 线程池服务模型,使用标准的阻塞式IO,预先创建一组线程处理请求。
			// TNonblockingServer – 多线程服务模型,使用非阻塞式IO(需使用TFramedTransport数据传输方式)
			// 处理大量更新的话,主要是在TThreadedServer和TNonblockingServer中进行选择。
			// TNonblockingServer能够使用少量线程处理大量并发连接,但是延迟较高;
			// TThreadedServer的延迟较低。
			// 实际中,TThreadedServer的吞吐量可能会比TNonblockingServer高,
			// 但是TThreadedServer的CPU占用要比TNonblockingServer高很多。
			TServerSocket serverTransport = new TServerSocket(SERVER_PORT);

			TServer.Args tArgs = new TServer.Args(serverTransport);

			tArgs.processor(tprocessor);

			// 支持的传输格式
			// TBinaryProtocol – 二进制格式.
			// TCompactProtocol – 压缩格式
			// TJSONProtocol – JSON格式
			// TSimpleJSONProtocol –提供JSON只写协议, 生成的文件很容易通过脚本语言解析。
			// TDebugProtocol – 使用易懂的可读的文本格式,以便于debug
			tArgs.protocolFactory(new TBinaryProtocol.Factory());// 传输格式,二进制
			// tArgs.protocolFactory(new TCompactProtocol.Factory()); // 传输格式,压缩
			// tArgs.protocolFactory(new TJSONProtocol.Factory());// 传输格式,JSON
			TServer server = new TSimpleServer(tArgs);
			server.serve();
			logger.info("启动完成.");

		} catch (TTransportException e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		Server server = new Server();
		server.startServer();
	}

}

 

Client 端:

package com.nanxiaoqiang.test.thrift.demo1;

import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
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 org.apache.thrift.transport.TTransportException;

public class Client {

    private static Logger logger = LogManager.getLogger(Client.class.getName());

    public static final String SERVER_IP = "localhost";
    public static final int SERVER_PORT = 9999;
    public static final int TIMEOUT = 30000;// 超时

    public Client() {
    }

    public void startclient() {
        // 支持的通信方式(数据传输方式)(Transport)
        // TFileTransport:文件(日志)传输类,允许client将文件传给server,允许server将收到的数据写到文件中。
        // THttpTransport:采用Http传输协议进行数据传输
        // TSocket:采用TCP Socket进行数据传输
        // TZlibTransport:压缩后对数据进行传输,或者将收到的数据解压
        // 下面几个类主要是对上面几个类地装饰(采用了装饰模式),以提高传输效率。
        // TBufferedTransport:对某个Transport对象操作的数据进行buffer,即从buffer中读取数据进行传输,或者将数据直接写入buffer
        // TFramedTransport:以frame为单位进行传输,非阻塞式服务中使用。同TBufferedTransport类似,也会对相关数据进行buffer,同时,它支持定长数据发送和接收。
        // TMemoryBuffer:从一个缓冲区中读写数据
        TTransport transport = new TSocket(SERVER_IP, SERVER_PORT, TIMEOUT);
        // 协议要和服务端一致
        TProtocol protocol = new TBinaryProtocol(transport);
        // TProtocol protocol = new TCompactProtocol(transport);
        // TProtocol protocol = new TJSONProtocol(transport);
        HelloworldService.Client client = new HelloworldService.Client(protocol);

        try {
            transport.open();

            // 测试1
            Helloworld h1 = null;
            boolean b1 = client.insertHelloworld(h1);
            logger.info("传输一个null值进行insertHelloworld方法,返回结果:" + b1);
            TimeUnit.SECONDS.sleep(1);

            // 测试2
            Helloworld h2 = new Helloworld();
            h2.setId(1);
            h2.setName("Hello World!Thrift!");
            boolean b2 = client.insertHelloworld(h2);
            logger.info("传输一个Helloworld对象进行insertHelloworld方法,返回结果:" + b2);
            TimeUnit.SECONDS.sleep(1);

            // 测试3
            Helloworld h3 = client.getHelloworld(0);
            logger.info("通过方法getHelloworld得到id为0的Helloworld对象,返回结果:"
                    + ToStringBuilder.reflectionToString(h3,
                            ToStringStyle.MULTI_LINE_STYLE));
            TimeUnit.SECONDS.sleep(1);

            // 测试4
            Helloworld h4 = client.getHelloworld(1);
            logger.info("通过方法getHelloworld得到id为1的Helloworld对象,返回结果:"
                    + ToStringBuilder.reflectionToString(h4,
                            ToStringStyle.MULTI_LINE_STYLE));
            TimeUnit.SECONDS.sleep(1);

            // 测试5
            // 此段会报错!不能返回null对象
            // 报错内容:org.apache.thrift.TApplicationException: getHelloworld failed: unknown result
            // Helloworld h5 = client.getHelloworld(2);
            // logger.info("通过方法getHelloworld得到id为2的Helloworld对象,返回结果:"
            // + ToStringBuilder.reflectionToString(h5,
            // ToStringStyle.MULTI_LINE_STYLE));
            // TimeUnit.SECONDS.sleep(1);

            // 测试6
            boolean b6 = client.removeHelloworld(0);
            logger.info("通过方法removeHelloworld删除id为0的Helloworld对象,返回结果:" + b6);
            TimeUnit.SECONDS.sleep(1);

            // 测试7
            boolean b7 = client.removeHelloworld(1);
            logger.info("通过方法removeHelloworld删除id为1的Helloworld对象,返回结果:" + b7);
            TimeUnit.SECONDS.sleep(1);

            // 测试8
            boolean b8 = client.removeHelloworld(2);
            logger.info("通过方法removeHelloworld删除id为2的Helloworld对象,返回结果:" + b8);
            TimeUnit.SECONDS.sleep(1);
           
        } catch (TTransportException e) {
            logger.error(e.getMessage());
            e.printStackTrace();
        } catch (TException e) {
            logger.error(e.getMessage());
            e.printStackTrace();
        } catch (InterruptedException e) {
            logger.error(e.getMessage());
            e.printStackTrace();
        } finally {
            if (transport != null)
                transport.close();
            logger.info("transport关闭");
        }

    }

    public static void main(String[] args) {
        Client c = new Client();
        c.startclient();
    }

}

 

然后分别运行Server和Client即可返回执行结果。

PS:

  1. 因为是测试,所以用的是单线程的Server,实际上最好用TNonblockingServer。
  2. null值是不能返回做交互的。会抛出org.apache.thrift.TApplicationException: getHelloworld failed: unknown result。

参考(受益良多):
http://www.cnblogs.com/mumuxinfei/p/3873709.html             Thrift 个人实战--初次体验Thrift
http://blog.csdn.net/amuseme_lu/article/details/6262572     Apache Thrift的简单使用
http://gemantic.iteye.com/blog/1199214                               thrift的使用介绍





 

分享到:
评论

相关推荐

    【Thrift之C++远程调用helloworld菜鸟教程】

    Thrift编译器会生成两个部分:一个接口头文件(如`helloworld_types.h`)和一个服务处理类(如`helloworld.cpp`)。接口头文件包含了数据结构的定义,而服务处理类则提供了服务接口的骨架代码,开发者需要在此基础上...

    thrift java hello

    这里定义了一个名为`HelloWorld`的服务,它有一个方法`sayHello`,返回一个字符串。 2. **生成代码**: 使用Thrift编译器将`hello.thrift`转换为Java源代码。在命令行中执行: ``` thrift -gen java hello....

    c# thrift demo

    Thrift是一种开源的跨语言服务开发框架,由Facebook于2007年发布,旨在提供高效、灵活且可扩展的远程过程调用(RPC)解决方案。它允许开发者定义服务接口和服务数据类型,然后自动生成支持多种编程语言的客户端和...

    Thrift的第一个例子

    这里定义了一个名为`HelloWorld`的服务,有一个方法`sayHello`,接受一个整型参数`numReps`,返回一个字符串。 接下来,我们需要使用Thrift编译器将IDL文件转换为目标语言的代码。假设我们的IDL文件名为`helloworld...

    Thrift demo

    - 服务定义的 IDL 文件(如 `helloworld.thrift`) - 编译后的服务接口和数据结构代码(如 `helloworld.py` 或 `helloworld.java`) - 服务器端实现(如 `server.py` 或 `server.java`) - 客户端示例(如 `...

    php_thrift_python安装测试记录

    在IT行业中,Thrift是一种高性能、可扩展的跨语言服务开发框架,由Facebook开源。它允许定义数据类型和服务接口,然后自动生成各种编程语言的代码,使得不同语言之间可以进行高效的数据交换和通信。本篇文章将围绕...

    thrift-delphi实例

    Thrift,全称为“Transportation Layer Security”,是由Facebook开源的一款高性能、跨语言的服务框架。它最初设计的目的是解决大规模分布式系统中的数据通信问题,通过定义一种中间表示(IDL,Interface Definition...

    thrift-laravel:Apache Thrift 教程 Hello World(服务器中的 Laravel + Python)

    教程在: 技术包括: 阿帕奇节俭 Laravel 4.2 Python 概念: BROWSERS WEB SERVER Apache Thrift | | | | hello? | | |--------------&gt;... | | Hello World! | | |&lt;--------------|

    Thrift使用示例代码

    Thrift是一种高性能、可扩展的跨语言服务开发框架,由Facebook开源。它的核心理念是提供一种简单的方式来定义服务,...在实际项目中,Thrift常用于构建大规模、高并发的微服务架构,为系统间的通信提供了坚实的基础。

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

    1. **Thrift IDL文件**:例如`helloworld.thrift`,它定义了一个服务接口,如`HelloService`,以及相关的数据类型,比如`HelloRequest`和`HelloResponse`。例如: ```thrift service HelloService { string ...

    Thrift双向通讯java代码

    以上就是Thrift双向通讯的基础步骤。在实际应用中,你可能还需要处理线程池、异步调用、异常处理、连接池等高级特性。Thrift还支持HTTP、HTTPS、Zookeeper等多种传输协议和调度策略,可以根据具体需求进行选择和配置...

    基于thrift的RPC调用实例

    在本实例中,我们将关注一个基于Thrift的RPC调用实现,Thrift是由Facebook开发的一种高效的跨语言服务开发框架。 Thrift的核心思想是定义一种中间描述文件(.thrift),该文件包含了服务接口、数据结构以及服务间的...

    采用java操作thrift代码示例

    在Java开发中,Thrift是一种高效、跨语言的服务框架,由Facebook开源,现已被Apache基金会维护。Thrift通过定义一种中间表示(IDL,接口定义语言)来描述服务,然后自动生成对应语言的客户端和服务器端代码,使得...

    Thrift初探:简单实现C#通讯服务程序

    这将在当前目录下生成C#代码,包括服务接口(如`MyService.cs`)、数据结构类(如果有的话)以及Thrift基础类库。 3. **实现服务** 在生成的`MyService.cs`中,你需要实现`IMyService`接口,提供`sayHello`方法的...

    Java Thrift demo例子

    Thrift是一种开源的跨语言服务开发框架,由Facebook于2007年开源,现由Apache基金会维护。它允许开发者定义服务接口,然后自动生成多种编程语言的代码,使得不同语言之间可以进行高效、可靠的RPC(远程过程调用)...

    基于thrift开发的客户端和服务端

    Thrift是一种开源的跨语言服务开发框架,由Facebook于2007年开发并贡献给了Apache基金会。它的主要目标是高效地实现不同编程语言之间的远程过程调用(RPC)。在这个"基于thrift开发的客户端和服务端"的示例中,我们...

    Thrift Java 服务器 客户端通信

    Thrift 是一个开源的跨语言服务开发框架,由Facebook于2007年推出,后来捐赠给了Apache软件基金会。Thrift的主要目标是高效地在不同的编程语言之间进行数据序列化和远程过程调用(RPC)。它通过定义一种中间表示...

    Thrift中实现Java与Python的RPC互相调用示例代码.rar

    在Python中,Thrift会生成一个`hello_world.py`文件,其中包含了服务的客户端和服务端类。 对于Java,你需要实现服务端接口,创建一个`Server`实例并启动监听。服务端代码可能会这样: ```java public class ...

    Apache Thrift 初学小讲(六)【spring】

    Apache Thrift 是一个开源的软件框架,用于构建可伸缩的、跨语言的服务。它结合了接口定义语言(IDL)和编译器,允许开发者定义服务接口,然后自动生成多种编程语言的代码,使得在不同语言之间进行高效的数据序列化...

    RPC-TEST:测试gRPC和Thrift的性能。 所有服务均由Java,Scala和Golang实施为HelloWorld

    简单的Thrift和gRPC性能测试使用一个简单的“ helloworld”原型来测试节俭和gRPC。 所有服务器和客户端均由Golang,Java和Scala实现测试结果如下(毫秒/ 10000次呼叫)。 第一个值使用一个客户端测试服务器,第二个...

Global site tag (gtag.js) - Google Analytics