一.什么是RPC?
RPC(Remote Procedure Call Protocol)——遠程過程調用協議,它是一種通過網絡從遠程計算機程序上請求服務,而不需要了解底層網絡技術的協議。
RPC協議假定某些傳輸協議的存在,如TCP或UDP,為通信程序之間攜帶信息數據。在OSI網絡通信模型中,RPC跨越了傳輸層和應用層。RPC使得開發包括網絡分布式多程序在內的應用程序更加容易。
二.什么是Thrift?
thrift是一個軟件框架,用來進行可擴展且跨語言的服務的開發。它結合了功能強大的軟件堆棧和代碼生成引擎,以構建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 這些編程語言間無縫結合的、高效的服務。
thrift最初由facebook開發,07年四月開放源碼,08年5月進入apache孵化器。
三.下載,安裝,配置Thrift
本機環境:ubuntu 12.04 (64bit)
1.下載:
下載地址: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.安裝,配置Thrift
官網教程:http://thrift.apache.org/docs/BuildingFromSource
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.
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基本概念
- 基本類型:
- 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實例
<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