中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

php使用thrift做服務端開發的案例

發布時間:2020-10-13 14:49:58 來源:億速云 閱讀:253 作者:小新 欄目:編程語言

小編給大家分享一下php使用thrift做服務端開發的案例,希望大家閱讀完這篇文章后大所收獲,下面讓我們一起去探討吧!

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 command 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支持),自動剔除無效的服務器

開發流程

1、定義IDL(Interface description language)接口描述文件,后綴.thrift

IDL規范:http://thrift.apache.org/docs/idl

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

2、服務端代碼開發

3、客戶端編寫接入代碼

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服務端

<?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做服務端開發的案例有了一定的了解,想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

青铜峡市| 沁水县| 凉山| 噶尔县| 张家川| 京山县| 会宁县| 阳城县| 遂溪县| 新乐市| 仙桃市| 金门县| 凯里市| 鄂尔多斯市| 广元市| 娄烦县| 三门峡市| 房产| 平潭县| 潮安县| 镇巴县| 石楼县| 黎川县| 平顶山市| 洛南县| 布尔津县| 河间市| 博野县| 扶余县| 镇平县| 阳谷县| 徐汇区| 忻州市| 本溪| 泰宁县| 丰镇市| 丹阳市| 崇礼县| 澎湖县| 孟连| 旺苍县|