Home > Article > Backend Development > Things about php using thrift for server-side development
php uses thrift for server-side development
Thrift uses interface description language to define and create services, and transmits data in binary format. It is smaller and more efficient. For high concurrency, Large data volumes and multi-language environments have better support.
What is Apache Thrift?
Apache Thrift is an extensible, cross-language service calling framework developed by FaceBook. To put it simply, you need to define a configuration file first. Different languages can use thrift to generate servers in their respective languages based on this configuration file. No matter what language the client uses, it can be called. In other words, based on the thrift protocol, Java can be used to call PHP. Serve. Currently supports calling each other between C, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml and Delphi and other languages.
Compared with traditional data transmission methods such as xml and json, thrift uses interface description language to define and create services, and transmits data in binary format. It is smaller and more efficient. For high concurrency and data volume, Large and multi-language environments have better support.
thrift installation environment requirements
g 4.2
boost 1.53.0
lex and yacc (based on flex and bison)
If lex and yacc are not installed, you must install them first, otherwise make will fail and prompt lex and yacc command not found error (general machines seem not to be installed, Ubuntu can use apt-get install flex bision).
Install thrift
Download the latest version of thrift:
wget http://www.apache.org/dyn/closer.cgi?path=/thrift/0.9.3/thrift-0.9.3.tar.gz tar xvf thrift-0.9.3.tar.gz cd thrift-0.9.3
2. Create the configure file
// 创建./configure文件 ./bootstrap.sh // 配置并安装 ./configure make // 检测是否有问题,如果机子没有安装python和java等可能会报错,不过本文主要讲php,安了php环境就行 make check make install
Compile options
Use ./configure --help to view options
If you want to disable a language, you can use ./configure -- without-java
thrift for php installation environment requires
php version >5.0, because the TBinaryProtocol protocol is used The pack() and unpack() functions are used to serialize data
You need to install the APC extension, because the TSocketPool class uses the apc_fetch() and apc_store() functions for apc cache operations.
When php uses thrift, in addition to copying the basic files in thrift/lib/php/lib to the project directory, you also need to copy the php files generated based on the configuration file. Go to the packages folder and introduce it into the project. This will be discussed in detail later.
Class library description
Data transmission format (protocol)
defines the transmission content and packaging of Thrift Type Unpacking, including:
TBinaryProtocol, binary format, TBinaryProtocolAccelerated is a fast packaging and unpacking that relies on the thrift_protocol extension.
TCompactProtocol, compression format
TJSONProtocol, JSON format
TMultiplexedProtocol, using the first three Data format interacts with a server that supports multiplexing protocols (providing multiple services at the same time, TMultiplexedProcessor)
Data transmission method (transport)
Defines how to send (write) and receive (read) data, including:
TBufferedTransport, cached transmission, written data does not start transmission immediately until the cache is refreshed.
TSocket, uses socket transmission
TFramedTransport, uses block mode for transmission, the specific transmission implementation depends on other transmission methods, such as TSocket
TCurlClient, uses curl to interact with the server
THttpClient, uses stream mode to interact with the HTTP server
TMemoryBuffer, use memory to exchange data
TPhpStream, use PHP standard input and output stream for transmission
TNullTransport, close data transmission
TSocketPool supports multiple server management based on TSocket (requires APC support) and automatically eliminates invalid servers
Development process
1. Define IDL (Interface description language) interface description file, suffix .thrift
IDL specification: http://thrift.apache.org/docs/idl
thrift types: http://thrift.apache.org/docs/types
2. Server-side code development
3. Client-side writing access code
IDL :
1.tutorial.thrift
include "shared.thrift" namespace php tutorial typedef i32 MyInteger const i32 INT32CONSTANT = 9853 const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'} enum Operation { ADD = 1, SUBTRACT = 2, MULTIPLY = 3, DIVIDE = 4 } struct Work { 1: i32 num1 = 0, 2: i32 num2, 3: Operation op, 4: optional string comment, } exception InvalidOperation { 1: i32 whatOp, 2: string why } service Calculator extends shared.SharedService { void ping(), i32 add(1:i32 num1, 2:i32 num2), i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch), oneway void zip() }
2.shared.thrift
namespace php shared struct SharedStruct { 1: i32 key 2: string value } service SharedService { SharedStruct getStruct(1: i32 key) }
php server
<?php namespace tutorial\php; ini_set('display_errors',1); error_reporting(E_ALL); // 引入类自动加载文件 require_once __DIR__.'/../../lib/php/lib/Thrift/ClassLoader/ThriftClassLoader.php'; // 载入自动加载类 use Thrift\ClassLoader\ThriftClassLoader; // 定义根据.thrift文件生成的php文件 $GEN_DIR = realpath(dirname(__FILE__).'/..').'/gen-php'; // 注册thrift服务 $loader = new ThriftClassLoader(); $loader->registerNamespace('Thrift', __DIR__ . '/../../lib/php/lib'); $loader->registerDefinition('shared', $GEN_DIR); $loader->registerDefinition('tutorial', $GEN_DIR); $loader->register(); if (php_sapi_name() == 'cli') { ini_set("display_errors", "stderr"); } use Thrift\Protocol\TBinaryProtocol; // 二进制格式打包解包 use Thrift\Transport\TPhpStream; // php流输入输出 use Thrift\Transport\TBufferedTransport; // 使用缓存 // 开始服务端逻辑 class CalculatorHandler implements \tutorial\CalculatorIf { protected $log = array(); public function ping() { error_log("ping()"); } // 相加 public function add($num1, $num2) { error_log("add({$num1}, {$num2})"); return $num1 + $num2; } // 枚举计算类型 public function calculate($logid, \tutorial\Work $w) { error_log("calculate({$logid}, {{$w->op}, {$w->num1}, {$w->num2}})"); switch ($w->op) { case \tutorial\Operation::ADD: $val = $w->num1 + $w->num2; break; case \tutorial\Operation::SUBTRACT: $val = $w->num1 - $w->num2; break; case \tutorial\Operation::MULTIPLY: $val = $w->num1 * $w->num2; break; case \tutorial\Operation::DIVIDE: if ($w->num2 == 0) { $io = new \tutorial\InvalidOperation(); $io->whatOp = $w->op; $io->why = "Cannot divide by 0"; throw $io; } $val = $w->num1 / $w->num2; break; default: $io = new \tutorial\InvalidOperation(); $io->whatOp = $w->op; $io->why = "Invalid Operation"; throw $io; } $log = new \shared\SharedStruct(); $log->key = $logid; $log->value = (string)$val; $this->log[$logid] = $log; return $val; } public function getStruct($key) { error_log("getStruct({$key})"); // This actually doesn't work because the PHP interpreter is // restarted for every request. //return $this->log[$key]; return new \shared\SharedStruct(array("key" => $key, "value" => "PHP is stateless!")); } public function zip() { error_log("zip()"); } }; header('Content-Type', 'application/x-thrift'); if (php_sapi_name() == 'cli') { echo "\r\n"; } $handler = new CalculatorHandler(); $processor = new \tutorial\CalculatorProcessor($handler); // 客户端和服务端在同一个输入输出流上 //1) cli 方式:php Client.php | php Server.php //2) cgi 方式:利用Apache或nginx监听http请求,调用php-fpm处理,将请求转换为PHP标准输入输出流 $transport = new TBufferedTransport(new TPhpStream(TPhpStream::MODE_R | TPhpStream::MODE_W)); $protocol = new TBinaryProtocol($transport, true, true); $transport->open(); $processor->process($protocol, $protocol); $transport->close(); //作为cli方式运行,非阻塞方式监听,基于libevent实现,非官方实现 //$transportFactory = new TBufferedTransportFactory(); //$protocolFactory = new TBinaryProtocolFactory(true, true); //$transport = new TNonblockingServerSocket('localhost', 9090); //$server = new TNonblockingServer($processor, $transport, $transportFactory, $transportFactory, $protocolFactory, $protocolFactory); //$server->serve(); //作为cli方式运行,监听端口,官方实现 //$transportFactory = new TBufferedTransportFactory(); //$protocolFactory = new TBinaryProtocolFactory(true, true); //$transport = new TServerSocket('localhost', 9090); //$server = new TSimpleServer($processor, $transport, $transportFactory, $transportFactory, $protocolFactory, $protocolFactory); //$server->serve();
php client
<?php namespace tutorial\php; error_reporting(E_ALL); require_once __DIR__.'/../../lib/php/lib/Thrift/ClassLoader/ThriftClassLoader.php'; use Thrift\ClassLoader\ThriftClassLoader; $GEN_DIR = realpath(dirname(__FILE__).'/..').'/gen-php'; $loader = new ThriftClassLoader(); $loader->registerNamespace('Thrift', __DIR__ . '/../../lib/php/lib'); $loader->registerDefinition('shared', $GEN_DIR); $loader->registerDefinition('tutorial', $GEN_DIR); $loader->register(); use Thrift\Protocol\TBinaryProtocol; use Thrift\Transport\TSocket; use Thrift\Transport\THttpClient; use Thrift\Transport\TBufferedTransport; use Thrift\Exception\TException; // 以上配置跟服务端类似 try { if (array_search('--http', $argv)) { // 使用http方式连接 $socket = new THttpClient('localhost', 8080, '/php/PhpServer.php'); } else { // 使用socket连接 $socket = new TSocket('localhost', 9090); } $transport = new TBufferedTransport($socket, 1024, 1024); $protocol = new TBinaryProtocol($transport); $client = new \tutorial\CalculatorClient($protocol); $transport->open(); $client->ping(); print "ping()\n"; $sum = $client->add(1,1); print "1+1=$sum\n"; // 调试异常情况 $work = new \tutorial\Work(); $work->op = \tutorial\Operation::DIVIDE; $work->num1 = 1; $work->num2 = 0; try { $client->calculate(1, $work); print "Whoa! We can divide by zero?\n"; } catch (\tutorial\InvalidOperation $io) { print "InvalidOperation: $io->why\n"; } $work->op = \tutorial\Operation::SUBTRACT; $work->num1 = 15; $work->num2 = 10; $diff = $client->calculate(1, $work); print "15-10=$diff\n"; $log = $client->getStruct(1); print "Log: $log->value\n"; $transport->close(); } catch (TException $tx) { print 'TException: '.$tx->getMessage()."\n"; }
Output:
// php client.php --http ping() 1+1=2 InvalidOperation: Cannot divide by 0 15-10=5 Log: PHP is stateless!
The above is the detailed content of Things about php using thrift for server-side development. For more information, please follow other related articles on the PHP Chinese website!