RPC學習----Thrift快速入門和Java簡單示例

一.什麼是RPC?

RPC(Remote Procedure Call Protocol)——遠程過程調用協議,它是一種經過網絡從遠程計算機程序上請求服務,而不須要了解底層網絡技術的協議。html

RPC協議假定某些傳輸協議的存在,如TCP或UDP,爲通訊程序之間攜帶信息數據。在OSI網絡通訊模型中,RPC跨越了傳輸層和應用層。RPC使得開發包括網絡分佈式多程序在內的應用程序更加容易。java

二.什麼是Thrift?

thrift是一個軟件框架,用來進行可擴展且跨語言的服務的開發。它結合了功能強大的軟件堆棧和代碼生成引擎,以構建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 這些編程語言間無縫結合的、高效的服務。python

thrift最初由facebook開發,07年四月開放源碼,08年5月進入apache孵化器。git

三.下載,安裝,配置Thrift

本機環境:ubuntu 12.04 (64bit)github

1.下載:apache

下載地址:http://www.apache.org/dyn/closer.cgi?path=/thrift/0.9.1/thrift-0.9.1.tar.gz (目前最新0.9.1,2014/08/11)編程

2.安裝,配置Thriftbootstrap

官網教程:http://thrift.apache.org/docs/BuildingFromSourceubuntu

Building from source

First make sure your system meets all necessary Apache Thrift Requirements網絡

If you are building from the first time out of the source repository, you will need to generate the configure scripts. (This is not necessary if you downloaded areleased tarball.) From the top directory, do:

./bootstrap.sh

Once the configure scripts are generated, thrift can be configured. From the top directory, do:

./configure

Disable a language:

./configure --without-java

You may need to specify the location of the boost files explicitly. If you installed boost in /usr/local, you would run configure as follows:

./configure --with-boost=/usr/local

If you want to override the logic of the detection of the Java SDK, use the JAVAC environment variable:

./configure JAVAC=/usb/bin/javac

Note that by default the thrift C++ library is typically built with debugging symbols included. If you want to customize these options you should use the CXXFLAGS option in configure, as such:

./configure CXXFLAGS='-g -O2'
./configure CFLAGS='-g -O2'
./configure CPPFLAGS='-DDEBUG_MY_FEATURE'

To see other configuration options run

./configure --help

Once you have run configure you can build Thrift via make:

make

and run the test suite:

make check

and the cross language test suite:

sh test/test.sh

Issues while compiling

  • "compiler/cpp/thriftl.cc:2190: undefined reference to `yywrap'"

    you need to install the Flex library (See also Apache Thrift Requirements ) and re-run the configuration script.

  • mv: cannot stat "'.deps/TBinaryProtocol.Tpo': No such file or directory" while building the Thrift Runtime Library

    Re-reun configure with

    --enable-libtool-lock

    or by turning off parallel make by placing .NOTPARALLEL: in lib/cpp/Makefile or

    make -j 1

    Although the thrift compiler build appears to be compatible with parallel make without libtool lock, the thrift runtime build is not.

Installing

From the top directory, become superuser and do:

make install

Note that some language packages must be installed manually using build tools better suited to those languages (this applies to Java, Ruby, PHP).

Look for the README file in the lib/<language>/ folder for more details on the installation of each language library package.

 

總結下來,第1步,先解壓thrift-0.9.1.tar.gz,解壓命令:
tar -xvf thrift-0.9.1.tar.gz

第2步,輸入如下命令:

$cd thrift-0.9.1
$./configure  
$make  
#sudo make install  

關於配置的問題能夠查看命令:

./configure --help

能夠關閉你不熟悉的語言,由於thrift支持的語言很是多,能夠關閉一些用不到的,如python,gt4等;

關閉命令爲:

./configure --without-qt4

在install的過程當中若是報一些test方面的error能夠忽略.

上面的步驟走完之後,能夠在任意一個目錄下輸入以下命令進行測試:

amosli@amosli-pc:~/workspace$ thrift -version
Thrift version 0.9.1

 

四.Thrift基本概念

1.數據類型
  • 基本類型:
    • bool:布爾值,true 或 false,對應 Java 的 boolean
    • byte:8 位有符號整數,對應 Java 的 byte
    • i16:16 位有符號整數,對應 Java 的 short
    • i32:32 位有符號整數,對應 Java 的 int
    • i64:64 位有符號整數,對應 Java 的 long
    • double:64 位浮點數,對應 Java 的 double
    • string:utf-8編碼的字符串,對應 Java 的 String
  • 結構體類型:
    • struct:定義公共的對象,相似於 C 語言中的結構體定義,在 Java 中是一個 JavaBean
  • 容器類型:
    • list:對應 Java 的 ArrayList
    • set:對應 Java 的 HashSet
    • map:對應 Java 的 HashMap
  • 異常類型:
    • exception:對應 Java 的 Exception
  • 服務類型:
    • service:對應服務的類

2.服務端編碼基本步驟:

  • 實現服務處理接口impl
  • 建立TProcessor
  • 建立TServerTransport
  • 建立TProtocol
  • 建立TServer
  • 啓動Server

3.客戶端編碼基本步驟:

  • 建立Transport
  • 建立TProtocol
  • 基於TTransport和TProtocol建立 Client
  • 調用Client的相應方法

4.數據傳輸協議

  • TBinaryProtocol : 二進制格式.
  • TCompactProtocol : 壓縮格式
  • TJSONProtocol : JSON格式
  • TSimpleJSONProtocol : 提供JSON只寫協議, 生成的文件很容易經過腳本語言解析

tips:客戶端和服務端的協議要一致

 
 

五.Java實例

1.引入jar包
我這裏用到的是maven進行管理jar包的,因此首先新建一個maven項目,而後在 pom.xml中添加以下內容:
  <dependency>
            <groupId>org.apache.thrift</groupId>
            <artifactId>libthrift</artifactId>
            <version>0.9.1</version>
  </dependency>
  <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.5.8</version>
 </dependency>

2.建立Thrift文件

建立Thrift文件:amosli@amosli-pc:/media/f91a4cca-0b96-4c30-b140-7918a196de3e/amosli/java/rpc/DemoTest/demoHello.thrift ,內容以下:

namespace java com.amos.thrift.demo

service  HelloWorldService {
  string sayHello(1:string username)
}

3.生成java文件:

thrift -r -gen java demoHello.thrift

文件目錄以下:

$ tree 
.
├── demoHello.thrift
└── gen-java
    └── com
        └── amos
            └── thrift
                └── demo
                    └── HelloWorldService.java

把生成的HelloWorldService.java文件拷貝到項目中去.

4.實現接口Iface

package com.amos;

/**
 * Created by amosli on 14-8-12.
 */
public class HelloWorldImpl implements HelloWorldService.Iface {

    public HelloWorldImpl() {
    }

    @Override
    public String sayHello(String username) {
        return "Hi," + username + " ,Welcome to the thrift's world !";
    }

}

5.TSimpleServer服務端

簡單的單線程服務模型,通常用於測試。

編寫服務端server代碼:HelloServerDemo.java

package com.amos;

import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;


/**
 * Created by amosli on 14-8-12.
 */
public class HelloServerDemo {
    public static final int SERVER_PORT = 8090;

    /**
     * @param args
     */
    public static void main(String[] args) {
        HelloServerDemo server = new HelloServerDemo();
        server.startServer();
    }

    public void startServer() {
        try {
            System.out.println("HelloWorld TSimpleServer start ....");

//          TProcessor tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>(new  HelloWorldImpl());
            HelloWorldService.Processor<HelloWorldService.Iface> tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>(new HelloWorldImpl());

            // 簡單的單線程服務模型,通常用於測試
            TServerSocket serverTransport = new TServerSocket(SERVER_PORT);
            TServer.Args tArgs = new TServer.Args(serverTransport);
            tArgs.processor(tprocessor);
//            tArgs.protocolFactory(new TBinaryProtocol.Factory());
            tArgs.protocolFactory(new TCompactProtocol.Factory());
            // tArgs.protocolFactory(new TJSONProtocol.Factory());
            TServer server = new TSimpleServer(tArgs);
            server.serve();

        } catch (Exception e) {
            System.out.println("Server start error!!!");
            e.printStackTrace();
        }
    }

}

6.編寫客戶端代碼

package com.amos;


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

/**
 * Created by amosli on 14-8-12.
 */
public class HelloClientDemo {

    public static final String SERVER_IP = "localhost";
    public static final int SERVER_PORT = 8090;
    public static final int TIMEOUT = 30000;

    /**
     * @param args
     */
    public static void main(String[] args) {
        HelloClientDemo client = new HelloClientDemo();
        client.startClient("amosli");

    }

    /**
     * @param userName
     */
    public void startClient(String userName) {
        TTransport transport = null;
        try {
            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);
            transport.open();
            String result = client.sayHello(userName);
            System.out.println("Thrift client result =: " + result);
        } catch (TTransportException e) {
            e.printStackTrace();
        } catch (TException e) {
            e.printStackTrace();
        } finally {
            if (null != transport) {
                transport.close();
            }
        }
    }

}

項目最終結構圖:

 

7.最終運行效果

服務端:

客戶端:

 

 

本文源碼:https://github.com/amosli/rpc

 

參考:

1.http://baike.baidu.com/view/1698865.htm?fr=aladdin

2.http://thrift.apache.org/docs/BuildingFromSource

3.http://www.micmiu.com/soa/rpc/thrift-sample/

4.http://blog.chinaunix.net/uid-20357359-id-2876170.html

5.http://baike.baidu.com/view/7287257.htm?fromtitle=RPC&fr=aladdin

相關文章
相關標籤/搜索