Thrift是一個軟件框架(遠程過程調用框架),用來進行可擴展且跨語言的服務的開發,封裝了數據傳輸格式(二進制、json)和網絡通訊的服務框架,提供多語言(C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml)的網絡服務器端和客戶端程序組件php
適用於搭建大型數據交換及存儲的通用工具,對於大型系統中的內部數據傳輸相對於JSON和xml不管在性能、傳輸大小上有明顯的優點。java
本文以註冊服務接口和登陸服務器接口爲教程,apache
Thrift開發的幾個概念:json
Server 服務模型api
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.penngo namespace php com.penngo struct 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
<?php namespace 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"; } ?>