Maison  >  Article  >  développement back-end  >  Choses à propos de PHP utilisant Thrift pour le développement côté serveur

Choses à propos de PHP utilisant Thrift pour le développement côté serveur

藏色散人
藏色散人avant
2020-10-12 14:26:014974parcourir

php utilise Thrift pour le développement côté serveur

Thrift utilise un langage de description d'interface pour définir et créer des services, et transmet les données au format binaire, qui est plus petit et plus efficace. la concurrence, les gros volumes de données et les environnements multilingues bénéficient d'une meilleure prise en charge.

Qu'est-ce qu'Apache Thrift ?

Apache Thrift est un framework d'appel de service extensible et multilingue développé par FaceBook. Pour faire simple, vous devez d'abord définir un fichier de configuration. Différentes langues peuvent utiliser Thrift pour générer des serveurs dans leurs propres langues en fonction de ce fichier de configuration. Quelle que soit la langue utilisée par le client, il peut être appelé. en d'autres termes, sur la base du protocole Thrift, Java peut appeler PHP Serve. Prend actuellement en charge les appels entre C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml et Delphi et d'autres langages.

Par rapport aux méthodes de transmission de données traditionnelles telles que XML et JSON, Thrift utilise un langage de description d'interface pour définir et créer des services, et transmet les données au format binaire. Il est plus petit et plus efficace pour une concurrence et un volume de données élevés. Les environnements vastes et multilingues bénéficient d’une meilleure prise en charge.

Exigences requises pour l'environnement d'installation d'épargne

  • g++ 4.2

  • boost 1.53.0

  • lex et yacc (basés sur flex et bison)

Si lex et yacc ne sont pas installés, vous devez d'abord les installer, sinon make échouera et vous demandera Erreur de commande lex et yacc introuvable (les machines générales ne semblent pas être installées, Ubuntu peut utiliser apt-get install flex bision).

Installer thrift

Téléchargez la dernière version de 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. Créez le fichier de configuration

// 创建./configure文件
./bootstrap.sh
// 配置并安装
./configure
make
// 检测是否有问题,如果机子没有安装python和java等可能会报错,不过本文主要讲php,安了php环境就行
make check
make install

Options de compilation

  • Utilisez ./configure --help pour afficher les options

  • Si vous souhaitez désactiver une langue, vous pouvez utilisez ./configure -- without-java

thrift pour les exigences de l'environnement d'installation php

  • php version>5.0, car le protocole TBinaryProtocol est utilisé. Les fonctions pack() et unpack() pour sérialiser les données

  • nécessitent l'installation de l'extension APC, car la classe TSocketPool utilise apc_fetch() et apc_store( ) fonctions pour les opérations de cache apc.

Lorsque php utilise thrift, en plus de copier les fichiers de base de thrift/lib/php/lib dans le répertoire du projet, vous devez également copier les fichiers php générés en fonction de la configuration Accédez au dossier packages et introduisez-le dans le projet. Cela sera discuté en détail plus tard.

Description de la bibliothèque de classes

Format de transmission des données (protocole)

définit le contenu de la transmission et le packaging du Thrift Type Unpacking, comprenant :

  • TBinaryProtocol, format binaire, TBinaryProtocolAccelerated est un packaging et un déballage rapides qui s'appuient sur l'extension thrift_protocol.

  • TCompactProtocol, format de compression

  • TJSONProtocol, format JSON

  • TMultiplexedProtocol, utilisant les trois premiers Le format de données interagit avec un serveur qui prend en charge les protocoles de multiplexage (fournissant plusieurs services en même temps, TMultiplexedProcessor)

Méthode de transmission de données (transport)

Définit comment envoyer (écrire) et recevoir (lire) des données, notamment :

  • TBufferedTransport, transmission en cache, les données écrites ne démarrent pas la transmission immédiatement tant que le cache n'est pas actualisé.

  • TSocket, utilise la transmission par socket

  • TFramedTransport, utilise le mode bloc pour la transmission, la mise en œuvre spécifique de la transmission dépend d'autres méthodes de transmission, telles que TSocket

  • TCurlClient, utilise curl pour interagir avec le serveur

  • THttpClient, utilise le mode flux pour interagir avec le serveur HTTP

  • TMemoryBuffer, utilise la mémoire pour échanger des données

  • TPhpStream, utilise le flux d'entrée et de sortie standard PHP pour la transmission

  • TNullTransport, désactiver la transmission des données

  • TSocketPool prend en charge la gestion de plusieurs serveurs basée sur TSocket (nécessite la prise en charge d'APC) et élimine automatiquement les serveurs non valides

Processus de développement

1. Définir le fichier de description de l'interface IDL (Interface description Language), suffixe .thrift

Spécification IDL : http://thrift.apache.org/docs/idl

Types d'épargne : http://thrift.apache.org/docs/types

2. Développement de code côté serveur

3. >

IDL :

1.tutorial.thrift

include "shared.thrift"
namespace php tutorial
typedef i32 MyInteger
const i32 INT32CONSTANT = 9853
const map<string,string> MAPCONSTANT = {&#39;hello&#39;:&#39;world&#39;, &#39;goodnight&#39;:&#39;moon&#39;}
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)
}

serveur php

<?php
namespace tutorial\php;
ini_set(&#39;display_errors&#39;,1);
error_reporting(E_ALL);
// 引入类自动加载文件
require_once __DIR__.&#39;/../../lib/php/lib/Thrift/ClassLoader/ThriftClassLoader.php&#39;;
// 载入自动加载类
use Thrift\ClassLoader\ThriftClassLoader;
// 定义根据.thrift文件生成的php文件
$GEN_DIR = realpath(dirname(__FILE__).&#39;/..&#39;).&#39;/gen-php&#39;;
// 注册thrift服务
$loader = new ThriftClassLoader();
$loader->registerNamespace(&#39;Thrift&#39;, __DIR__ . &#39;/../../lib/php/lib&#39;);
$loader->registerDefinition(&#39;shared&#39;, $GEN_DIR);
$loader->registerDefinition(&#39;tutorial&#39;, $GEN_DIR);
$loader->register();
if (php_sapi_name() == &#39;cli&#39;) {
  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&#39;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(&#39;Content-Type&#39;, &#39;application/x-thrift&#39;);
if (php_sapi_name() == &#39;cli&#39;) {
  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(&#39;localhost&#39;, 9090);
//$server = new TNonblockingServer($processor, $transport, $transportFactory, $transportFactory, $protocolFactory, $protocolFactory);
//$server->serve();
//作为cli方式运行,监听端口,官方实现
//$transportFactory = new TBufferedTransportFactory();
//$protocolFactory = new TBinaryProtocolFactory(true, true);
//$transport = new TServerSocket(&#39;localhost&#39;, 9090);
//$server = new TSimpleServer($processor, $transport, $transportFactory, $transportFactory, $protocolFactory, $protocolFactory);
//$server->serve();

client php

<?php
namespace tutorial\php;
error_reporting(E_ALL);
require_once __DIR__.&#39;/../../lib/php/lib/Thrift/ClassLoader/ThriftClassLoader.php&#39;;
use Thrift\ClassLoader\ThriftClassLoader;
$GEN_DIR = realpath(dirname(__FILE__).&#39;/..&#39;).&#39;/gen-php&#39;;
$loader = new ThriftClassLoader();
$loader->registerNamespace(&#39;Thrift&#39;, __DIR__ . &#39;/../../lib/php/lib&#39;);
$loader->registerDefinition(&#39;shared&#39;, $GEN_DIR);
$loader->registerDefinition(&#39;tutorial&#39;, $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(&#39;--http&#39;, $argv)) {
  // 使用http方式连接
    $socket = new THttpClient(&#39;localhost&#39;, 8080, &#39;/php/PhpServer.php&#39;);
  } else {
    // 使用socket连接
    $socket = new TSocket(&#39;localhost&#39;, 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 &#39;TException: &#39;.$tx->getMessage()."\n";
}

Sortie :

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer