关于php使用thrift做服务端开发的那些事-php教程

资源魔 39 0
php应用thrift做效劳端开发

thrift采纳接口形容言语界说以及创立效劳,用二进制格局传输数据,体积更小、效率更高,关于高并发、数据量年夜以及多言语的环境有更好的支持。

Apache Thrift是啥?

Apache Thrift是FaceBook开发的一套可扩大的、跨言语的效劳挪用框架。简略的说就是先界说一个设置装备摆设文件,没有同的言语能够行使thrift基于这个设置装备摆设文件天生各自言语的效劳端,不论客户端用甚么言语,均可以挪用,也就是说基于thrift协定用java能够挪用php的效劳。今朝支持C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml and Delphi等言语之间互相挪用。

绝对于传统的xml以及json等数据传输形式来讲,thrift采纳接口形容言语界说以及创立效劳,用二进制格局传输数据,体积更小、效率更高,关于高并发、数据量年夜以及多言语的环境有更好的支持。

thrift装置环境要求

  • g++ 4.2

  • boost 1.53.0

  • lex and yacc(基于flex以及bison)

假如没装置lex以及yacc的话要先装置,不然会make失败,提醒lex以及yacc co妹妹and not found谬误(普通的机械貌似都没安,Ubuntu用apt-get install flex bision便可)。

装置thrift

下载最新版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.创立configure文件

// 创立./configure文件
./bootstrap.sh
// 设置装备摆设并装置
./configure
make
// 检测能否有成绩,假如机子不装置python以及java等可能会报错,不外本文次要讲php,安了php环境就行
make check
make install

编译选项

  • 应用./configure --help能够查看选项

  • 假如想禁用某个言语,能够用./configure --without-java

thrift for php装置环境要求

  • php版本>5.0,由于TBinaryProtocol协定用到了pack()以及unpack()函数来序列化数据

  • 需求装置APC扩大,由于TSocketPool这个类用到了apc_fetch()以及apc_store()函数进行apc缓存操作。

php应用thrift的时分,除了了要将thrift/lib/php/lib里的根底文件copy到名目目次下,还需求将依据设置装备摆设文件天生的php文件也copy到packages文件夹下,并引入到名目中,这个后续会具体讲。

类库阐明

数据传输格局(protocol)

界说的了传输内容,对Thrift Type的打包解包,包罗:

  • TBinaryProtocol,二进制格局,TBinaryProtocolAccelerated则是依赖于thrift_protocol扩大的疾速打包解包。

  • TCompactProtocol,紧缩格局

  • TJSONProtocol,JSON格局

  • TMultiplexedProtocol,行使前三种数据格局与支持多路复用协定的效劳端(同时提供多个效劳,TMultiplexedProcessor)交互

数据传输形式(transport)

界说了若何发送(write)以及接纳(read)数据,包罗:

  • TBufferedTransport,缓存传输,写入数据其实不立刻开端传输,直到刷新缓存。

  • TSocket,应用socket传输

  • TFramedTransport,采纳分块形式进行传输,详细传输完成依赖其余传输形式,比方TSocket

  • TCurlClient,应用curl与效劳端交互

  • THttpClient,采纳stream形式与HTTP效劳端交互

  • TMemoryBuffer,应用内存形式替换数据

  • TPhpStream,应用PHP规范输出输入流进行传输

  • TNullTransport,封闭数据传输

  • TSocketPool正在TSocket根底支持多个效劳端治理(需求APC支持),主动剔除了有效的效劳器

开发流程

一、界说IDL(Interface description language)接口形容文件,后缀.thrift

IDL标准:http://thrift.apache.org/docs/idl

thrift types:http://thrift.apache.org/docs/types

二、效劳端代码开发

三、客户端编写接入代码

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 co妹妹ent,
}
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效劳端

<?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客户端

<?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";
}

输入:

// php client.php --http
ping()
1+1=2
InvalidOperation: Cannot divide by 0
15-10=5
Log: PHP is stateless!

以上就是对于php应用thrift做效劳端开发的那些事的具体内容,更多请存眷资源魔其它相干文章!

标签: php php开发教程 php开发资料 php开发自学 thrift

抱歉,评论功能暂时关闭!