標籤:
Thrift是一個軟體架構(遠端程序呼叫架構),用來進行可擴充且跨語言的服務的開發,封裝了資料轉送格式(二進位、json)和網路通訊的服務架構,提供多語言(C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml)的網路伺服器端和用戶端程式組件
適用於搭建大型資料交換及儲存的通用工具,對於大型系統中的內部資料轉送相對於JSON和xml無論在效能、傳輸大小上有明顯的優勢。
本文以註冊服務介面和登入伺服器介面為教程,
Thrift開發的幾個概念:
Server 服務模型
Handler 資料處理介面
Processor 資料處理對象
Protocol 資料轉送協議
Transport 資料轉送方式
(1)支援的傳輸格式
TBinaryProtocol – 二進位格式.
TCompactProtocol – 壓縮格式
TJSONProtocol – JSON格式
TSimpleJSONProtocol –提供JSON唯寫協議, 產生的檔案很容易通過指令碼語言解析。
TDebugProtocol – 使用易懂的可讀的文字格式設定,以便於debug
(2) 支援的通訊方式(資料轉送方式)(Transport)
TFileTransport:檔案(日誌)傳輸類,允許client將檔案傳給server,允許server將收到的資料寫到檔案中。
THttpTransport:採用Http傳輸協議進行資料轉送
TSocket:採用TCP Socket進行資料轉送
TZlibTransport:壓縮後對資料進行傳輸,或者將收到的資料解壓
下面幾個類主要是對上面幾個類地裝飾(採用了裝飾模式),以提高傳輸效率。
TBufferedTransport:對某個Transport對象操作的資料進行buffer,即從buffer中讀取資料進行傳輸,或者將資料直接寫入buffer
TFramedTransport:以frame為單位進行傳輸,非阻塞式服務中使用。同TBufferedTransport類似,也會對相關資料進行buffer,同時,它支援定長資料發送和接收。
TMemoryBuffer:從一個緩衝區中讀寫資料
(3)支援的服務模型
TSimpleServer – 簡單的單線程服務模型,常用於測試
TThreadedServer - 多線程服務模型,使用阻塞式IO,每個請求建立一個線程。
TThreadPoolServer – 線程池服務模型,使用標準的阻塞式IO,預先建立一組線程處理請求。
TNonblockingServer – 多線程服務模型,使用非阻塞式IO(需使用TFramedTransport資料轉送方式)
處理大量更新的話,主要是在TThreadedServer和TNonblockingServer中進行選擇。TNonblockingServer能夠使用少量線程處理大量並發串連,但是延遲較高;TThreadedServer的延遲較低。實際中,TThreadedServer的輸送量可能會比TNonblockingServer高,但是TThreadedServer的CPU佔用要比TNonblockingServer高很多。
服務端編寫的一般步驟:
1. 建立Handler
2. 基於Handler建立Processor
3. 建立Transport(通訊方式)
4. 建立Protocol方式(設定傳輸格式)
5. 基於Processor, Transport和Protocol建立Server
6. 運行Server
用戶端編寫的一般步驟:
1. 建立Transport
2. 建立Protocol方式
3. 基於Transport和Protocol建立Client
4. 運行Client的方法
上邊概述內容參考自:http://elf8848.iteye.com/blog/1960131
下面開始正式代碼教程
服務描述檔案test.thrift,定義了login服務和register
/** * The first thing to know about are types. The available types in Thrift are: * * bool Boolean, one byte * byte Signed byte * i16 Signed 16-bit integer * i32 Signed 32-bit integer * i64 Signed 64-bit integer * double 64-bit floating point value * string String * binary Blob (byte array) * map<t1,t2> Map from one type to another * list<t1> Ordered list of one type * set<t1> Set of unique elements of one type * * Did you also notice that Thrift supports C style comments? */namespace java com.penngonamespace php com.penngostruct User {1: i64 id,2: string name,3: string password}service LoginService{ User login(1:string name, 2:string psw);} service RegisterService{ User createUser(1:string name, 2:string psw);}
使用thrift產生對應平台語言代碼
thrift -gen java test.thrift
thrift -gen php test.thrift
如果php需要產生伺服器端,需求改為thrift -gen php:server test.thrift
java
實現LoginServiceImpl.java登入介面業務
import org.apache.thrift.TException;public class LoginServiceImpl implements LoginService.Iface{public LoginServiceImpl(){}public User login(String name, String psw) throws TException{User user = null;if(name.equals("penngo") && psw.equals("123")){user = new User();user.setId(1);user.setName("penngo");}return user;}}
實現RegisterServiceImpl.java註冊介面業務
import org.apache.thrift.TException;public class RegisterServiceImpl implements RegisterService.Iface{public RegisterServiceImpl(){}public User createUser(String name, String psw) throws TException{User user = new User();user.setId(2);user.setName(name);user.setPassword(psw);return user;}}
伺服器端java代碼
package com.penngo.main;import org.apache.thrift.TMultiplexedProcessor;import org.apache.thrift.server.TServer;import org.apache.thrift.server.TThreadPoolServer;import org.apache.thrift.transport.TServerSocket;import org.apache.thrift.transport.TTransportException;import com.penngo.LoginService;import com.penngo.LoginServiceImpl;import com.penngo.RegisterService;import com.penngo.RegisterServiceImpl;public class Server {private void start() {try {TServerSocket serverTransport = new TServerSocket(7911);// 使用者登入LoginService.Processor loginProcessor = new LoginService.Processor(new LoginServiceImpl());// 使用者註冊RegisterService.Processor registerProcessor = new RegisterService.Processor(new RegisterServiceImpl());// Factory protFactory = new TBinaryProtocol.Factory(true, true);// TServer server = new TThreadPoolServer(new// TThreadPoolServer.Args(serverTransport)// .processor(loginProcessor));TMultiplexedProcessor processor = new TMultiplexedProcessor();processor.registerProcessor("LoginService", loginProcessor);processor.registerProcessor("RegisterService", registerProcessor);TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor));System.out.println("Starting server on port 7911 ...");server.serve();} catch (TTransportException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}}public static void main(String args[]) {Server srv = new Server();srv.start();}}
用戶端java
package com.penngo.main;import org.apache.thrift.*;import org.apache.thrift.protocol.*;import org.apache.thrift.transport.*;import com.penngo.LoginService;import com.penngo.RegisterService;import com.penngo.User;public class Client {public static void main(String[] args) {try {TTransport transport = new TSocket("localhost", 7911);TProtocol protocol = new TBinaryProtocol(transport);TMultiplexedProtocol mp1 = new TMultiplexedProtocol(protocol,"LoginService");// TProtocol protocol = new TBinaryProtocol(transport);// LoginService.Client client = new LoginService.Client(protocol);LoginService.Client loginClient = new LoginService.Client(mp1);TMultiplexedProtocol mp2 = new TMultiplexedProtocol(protocol,"RegisterService");RegisterService.Client registerClient = new RegisterService.Client(mp2);transport.open();User user = loginClient.login("penngo", "123");if (user != null) {System.out.println("登入成功:" + user.getId() + " "+ user.getName());} else {System.out.println("登入失敗");}User user2 = registerClient.createUser("test", "123");if (user2 != null) {System.out.println("建立使用者成功:" + user2.getId() + " "+ user2.getName());} else {System.out.println("建立使用者失敗");}transport.close();} catch (TException x) {x.printStackTrace();}}}
用戶端php
<?phpnamespace com\penngo;require_once __DIR__.‘/../../lib/Thrift/ClassLoader/ThriftClassLoader.php‘;//echo __DIR__.‘/../../lib/Thrift/ClassLoader/ThriftClassLoader.php‘;use Thrift\ClassLoader\ThriftClassLoader;$GEN_DIR = realpath(dirname(__FILE__)).‘/../../gen-php‘;$loader = new ThriftClassLoader();$loader->registerNamespace(‘Thrift‘, __DIR__ . ‘/../../lib‘);//$loader->registerDefinition(‘shared‘, $GEN_DIR);$loader->registerDefinition(‘com‘, $GEN_DIR);$loader->register();if (php_sapi_name() == ‘cli‘) { ini_set("display_errors", "stderr");}use Thrift\Protocol\TBinaryProtocol;use Thrift\Protocol\TMultiplexedProtocol;use Thrift\Transport\TSocket;use Thrift\Transport\THttpClient;use Thrift\Transport\TBufferedTransport;use Thrift\Exception\TException;use com\penngo\RegisterServiceClient;use com\penngo\LoginServiceClient;try { if (array_search(‘--http‘, $argv)) { //$socket = new THttpClient(‘localhost‘, 8080, ‘/php/PhpServer.php‘); } else { $socket = new TSocket(‘localhost‘, 7911); } $transport = new TBufferedTransport($socket, 1024, 1024); $protocol = new TBinaryProtocol($transport); $loginProtocol = new TMultiplexedProtocol($protocol, "LoginService"); $registerProtocol = new TMultiplexedProtocol($protocol, "RegisterService"); $loginClient = new LoginServiceClient($loginProtocol); $registerClient = new RegisterServiceClient($registerProtocol); $transport->open(); $user = $loginClient->login(‘penngo‘, ‘123‘); print "user===={$user->id} {$user->name} \n"; $user = $registerClient->createUser(‘test‘, ‘123456‘); print "user===={$user->id} {$user->name} \n"; $transport->close();} catch (TException $tx) { print ‘TException: ‘.$tx->getMessage()."\n"; print ‘TException: ‘.$tx->getTraceAsString()."\n";}?>
Thrift的java和php資料互動