zoukankan      html  css  js  c++  java
  • Thrift(PHP)入门无错篇章(一)

    一、安装篇

    博主注:截至2017-10-10,官网上thrift最新版0.10.0一直无法成功编译。所以,请选择0.9.3版本,避免走各种弯路:

    wget http://apache.fayea.com/thrift/0.9.3/thrift-0.9.3.tar.gz

    1、安装开发平台工具

    yum -y groupinstall "Development Tools"

    2、安装autoconf

    wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
    tar xvf autoconf-2.69.tar.gz
    cd autoconf-2.69
    ./configure --prefix=/usr/local
    make
    make install

    3、安装automake

    wget http://ftp.gnu.org/gnu/automake/automake-1.14.tar.gz
    tar xvf automake-1.14.tar.gz
    cd automake-1.14
    ./configure --prefix=/usr/local
    make
    make install

    4、安装bison

    wget http://ftp.gnu.org/gnu/bison/bison-2.5.1.tar.gz
    tar xvf bison-2.5.1.tar.gz
    cd bison-2.5.1
    ./configure --prefix=/usr/local
    make
    make install

    5、安装C++库依赖包

    yum -y install libevent-devel zlib-devel openssl-devel

    6、安装boost

    wget http://sourceforge.net/projects/boost/files/boost/1.53.0/boost_1_53_0.tar.gz
    tar xvf boost_1_53_0.tar.gz
    cd boost_1_53_0
    ./bootstrap.sh
    ./b2

    7、安装其它依赖包

    yum install gcc gcc-c++ bzip2 bzip2-devel bzip2-libs python-devel -y

    8、安装thrift(基本的编译套路)

    cd thrift
    ./bootstrap.sh
    ./configure --with-lua=no --prefix=/alidata/server/thrift
    make
    make install

    二、Hello World篇

    使用套路总结:

    1、用IDL语法,定义自己的数据结构与服务接口:

    https://git-wip-us.apache.org/repos/asf?p=thrift.git;a=blob_plain;f=tutorial/tutorial.thrift
    https://git-wip-us.apache.org/repos/asf?p=thrift.git;a=blob_plain;f=tutorial/shared.thrift

    将这两个文件下载到本地,分别保存为tutorial.thrift和shared.thrift,并将这两个文件传到与thrift同目录下。

    附:

    IDL详细教程:http://thrift.apache.org/docs/idl

    IDL示例(够用了):https://git-wip-us.apache.org/repos/asf?p=thrift.git;a=blob_plain;f=tutorial/tutorial.thrift

                                     https://git-wip-us.apache.org/repos/asf?p=thrift.git;a=blob_plain;f=tutorial/shared.thrift

    2、用thrift将上面的thrift的IDL文件,转成对应语言的类:

    thrift -gen php:server tutorial.thrift

    上面这一句是对应服务端的转换,客户端的转换不用:server;但是服务端方式生成的类文件可以供客户端使用。

    3、转换完成后,在本目录下会得到一个gen-php目录,里面有三个文件tutorial.php、shared.php和Types.php。

    tutorial.php里面有一个CalculatorIf接口,这个类是我们要实现的服务端业务接口。

    shared.php被引用在tutorial.php文件中。

    Types.php里面是自定义数据类型。

    4、实现server端,即需要创建一个Handler类实再业务接口CalculatorIf

    注意:这里的lib文件在thrift源码包lib里,我们移到自己的php需要的路径中。代码中require_once部分、$GEN_DIR部分、Thrift命名空间注册部分的路径需要根据实际情况进行更改

    <?php
    
    namespace tutorialphp;
    
    error_reporting(E_ALL);
    
    require_once __DIR__.'/../../lib/php/lib/Thrift/ClassLoader/ThriftClassLoader.php';
    
    use ThriftClassLoaderThriftClassLoader;
    
    $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();
    
    
    if (php_sapi_name() == 'cli') {
      ini_set("display_errors", "stderr");
    }
    
    use ThriftProtocolTBinaryProtocol;
    use ThriftTransportTPhpStream;
    use ThriftTransportTBufferedTransport;
    
    class CalculatorHandler implements 	utorialCalculatorIf {
      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, 	utorialWork $w) {
        error_log("calculate({$logid}, {{$w->op}, {$w->num1}, {$w->num2}})");
        switch ($w->op) {
          case 	utorialOperation::ADD:
            $val = $w->num1 + $w->num2;
            break;
          case 	utorialOperation::SUBTRACT:
            $val = $w->num1 - $w->num2;
            break;
          case 	utorialOperation::MULTIPLY:
            $val = $w->num1 * $w->num2;
            break;
          case 	utorialOperation::DIVIDE:
            if ($w->num2 == 0) {
              $io = new 	utorialInvalidOperation();
              $io->whatOp = $w->op;
              $io->why = "Cannot divide by 0";
              throw $io;
            }
            $val = $w->num1 / $w->num2;
            break;
          default:
            $io = new 	utorialInvalidOperation();
            $io->whatOp = $w->op;
            $io->why = "Invalid Operation";
            throw $io;
        }
    
        $log = new sharedSharedStruct();
        $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 sharedSharedStruct(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 "
    ";
    }
    
    $handler = new CalculatorHandler();
    $processor = new 	utorialCalculatorProcessor($handler);
    
    $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();

    5、实现client端:

    同样需要注意:这里的lib文件在thrift源码包lib里,我们移到自己的php需要的路径中。代码中require_once部分、$GEN_DIR部分、Thrift命名空间注册部分的路径需要根据实际情况进行更改

    <?php
    
    namespace tutorialphp;
    
    error_reporting(E_ALL);
    
    require_once __DIR__.'/../../lib/php/lib/Thrift/ClassLoader/ThriftClassLoader.php';
    
    use ThriftClassLoaderThriftClassLoader;
    
    $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 ThriftProtocolTBinaryProtocol;
    use ThriftTransportTSocket;
    use ThriftTransportTHttpClient;
    use ThriftTransportTBufferedTransport;
    use ThriftExceptionTException;
    
    try {
      if (array_search('--http', $argv)) {
        $socket = new THttpClient('localhost', 8080, '/php/PhpServer.php');
      } else {
        $socket = new TSocket('localhost', 9090);
      }
      $transport = new TBufferedTransport($socket, 1024, 1024);
      $protocol = new TBinaryProtocol($transport);
      $client = new 	utorialCalculatorClient($protocol);
    
      $transport->open();
    
      $client->ping();
      print "ping()
    ";
    
      $sum = $client->add(1,1);
      print "1+1=$sum
    ";
    
      $work = new 	utorialWork();
    
      $work->op = 	utorialOperation::DIVIDE;
      $work->num1 = 1;
      $work->num2 = 0;
    
      try {
        $client->calculate(1, $work);
        print "Whoa! We can divide by zero?
    ";
      } catch (	utorialInvalidOperation $io) {
        print "InvalidOperation: $io->why
    ";
      }
    
      $work->op = 	utorialOperation::SUBTRACT;
      $work->num1 = 15;
      $work->num2 = 10;
      $diff = $client->calculate(1, $work);
      print "15-10=$diff
    ";
    
      $log = $client->getStruct(1);
      print "Log: $log->value
    ";
    
      $transport->close();
    
    } catch (TException $tx) {
      print 'TException: '.$tx->getMessage()."
    ";
    }
    
    ?>

    6、因为php的server端代码没有进行端口侦听的网络服务功能,所以要依靠python来提供这个功能。我们把下面的脚本命名为s.py,需要与server.php放在同一个目录下(/alidata/www/thrift)

    #!/bin/py
    #coding=utf-8
    
    import os
    import BaseHTTPServer
    import CGIHTTPServer
    # chdir(2) into the tutorial directory.
    os.chdir('/alidata/www/thrift')
    # 指定目录 ,如果目录错误 请求会失败
    class Handler(CGIHTTPServer.CGIHTTPRequestHandler):
        cgi_directories  = ['/']
    
    BaseHTTPServer.HTTPServer(('', 8080), Handler).serve_forever()

    7、到现在为止,hello world级别的工程已经完成。

    运行服务端s.py

    运行客户端php client.php --http

    便可以看到响应的实际效果

    三、生产使用篇

    hello world级别的工程,只有一个进程进行侦听和服务,在多核CPU的时代,只有一个进程不但无法充分利用CPU的性能,也无法为用户提供最高效的服务。

    方案一:用php自己实现网络服务方案(这是一个牛人写的多进程服务demo,完全可以参照)  http://blog.csdn.net/flynetcn/article/details/47837975

    <?php  
    /** 
     * 多进程形式的server. 
     * @package thrift.server 
     * @author flynetcn 
     */  
    namespace ThriftServer;  
      
    use ThriftServerTServer;  
    use ThriftTransportTTransport;  
    use ThriftExceptionTException;  
    use ThriftExceptionTTransportException;  
      
    class TMultiProcessServer extends TServer  
    {  
        /** 
         * 捕获的信号编号 
         */  
        static $catchQuitSignal = 0;  
      
        /** 
         * worker进程数量 
         */  
        private $workProcessNum = 4;  
      
        /** 
         * 每个worker进程处理的最大请求数 
         */  
        private $maxWorkRequestNum = 2000;  
      
        /** 
         * 当前worker进程已处理的请求数 
         */  
        private $currentWorkRequestNum = 0;  
          
        /** 
         * 当前连接调用次数 
         */  
        private $currentConnectCallNum = 0;  
      
        /** 
         * 发送超时 
         */  
        private $sendTimeoutSec = 1;  
      
        /** 
         * 接收超时 
         */  
        private $recvTimeoutSec = 1;  
      
        /** 
         * 当前进程pid 
         */  
        private $pid = 0;  
      
        /** 
         * Flag for the main serving loop 
         */  
        private $stop_ = false;  
      
        /** 
         * List of children. 
         */  
        protected $childrens = array();  
      
        /** 
         * 服务器日志文件 
         */  
        protected static $logFiles;  
        protected static $pidFile;  
      
        /** 
         * run 
         */   
        public function serve($daemon=false, array $config=array())  
        {  
            if (isset($config['workProcessNum'])) {  
                $this->workProcessNum = intval($config['workProcessNum']);  
            }  
            if ($this->workProcessNum < 1) {  
                self::log(1, "child workProcessNum can not be less than 1");  
                throw new TException('child workProcessNum can not be less than 1');  
            }  
            if (isset($config['maxWorkRequestNum'])) {  
                $this->maxWorkRequestNum = intval($config['maxWorkRequestNum']);  
            }  
            if ($this->maxWorkRequestNum < 1) {  
                self::log(1, "child maxWorkRequestNum can not be less than 1");  
                throw new TException('child maxWorkRequestNum can not be less than 1');  
            }  
            if (isset($config['sendTimeoutSec'])) {  
                $this->sendTimeoutSec = intval($config['sendTimeoutSec']);  
            }  
            if (isset($config['recvTimeoutSec'])) {  
                $this->recvTimeoutSec = intval($config['recvTimeoutSec']);  
            }  
            if ($daemon) {  
                $this->daemon();  
                $this->registerSignalHandler();  
                self::$logFiles = isset($config['logFiles']) && is_array($config['logFiles']) ? $config['logFiles'] : array();  
                self::$pidFile = isset($config['pidFile']) ? $config['pidFile'] : '';  
                declare(ticks=3);  
            }  
            $this->pid = posix_getpid();  
            self::createPidFile($this->pid);  
            self::log(0, "manage process({$this->pid}) has started");  
            $this->transport_->listen();  
            while (!$this->stop_) {  
                while ($this->workProcessNum > 0) {  
                    try {  
                        $pid = pcntl_fork();  
                        if ($pid > 0) {  
                            $this->handleParent($pid, $this->workProcessNum);  
                        } else if ($pid === 0) {  
                            $this->pid = posix_getpid();  
                            $this->handleChild($this->workProcessNum);  
                        } else {  
                            self::log(1, "Failed to fork");  
                            throw new TException('Failed to fork');  
                        }  
                        $this->workProcessNum--;  
                    } catch (Exception $e) {  
                    }  
                }  
                $this->collectChildren();  
                sleep(2);  
                if (ThriftServerTMultiProcessServer::$catchQuitSignal) {  
                    $this->stop();  
                }  
            }  
        }  
          
        public function getCurrentWorkRequestNum()  
        {  
            return $this->currentWorkRequestNum;  
        }  
          
        public function getCurrentConnectCallNum()  
        {  
            return $this->currentConnectCallNum;  
        }  
      
        /** 
         * Code run by the parent 
         * 
         * @param int $pid 
         * @param int $num 进程编号 
         * @return void 
         */  
        private function handleParent($pid, $num)  
        {  
            $this->childrens[$pid] = $num;  
        }  
      
        /** 
         * Code run by the child. 
         * 
         * @param int $num 进程编号 
         * @return void 
         */  
        private function handleChild($num)  
        {  
            self::log(0, "child process($this->pid) has started");  
            $this->childrens = array();  
            while (!$this->stop_) {  
                try {  
                    $transport = $this->transport_->accept();  
                    if ($transport != null) {  
                        $transport->setSendTimeout($this->sendTimeoutSec * 1000);  
                        $transport->setRecvTimeout($this->recvTimeoutSec * 1000);  
                        $this->currentWorkRequestNum++;  
                        $this->currentConnectCallNum = 0;  
                        $inputTransport = $this->inputTransportFactory_->getTransport($transport);  
                        $outputTransport = $this->outputTransportFactory_->getTransport($transport);  
                        $inputProtocol = $this->inputProtocolFactory_->getProtocol($inputTransport);  
                        $outputProtocol = $this->outputProtocolFactory_->getProtocol($outputTransport);  
                        while ($this->processor_->process($inputProtocol, $outputProtocol)) {  
                            $this->currentConnectCallNum++;  
                        }  
                        @$transport->close();  
                    }  
                } catch (TTransportException $e) {  
                } catch (Exception $e) {  
                    self::log(1, $e->getMessage().'('.$e->getCode().')');  
                }  
                if (ThriftServerTMultiProcessServer::$catchQuitSignal) {  
                    $this->stop();  
                }  
                if ($this->currentWorkRequestNum >= $this->maxWorkRequestNum) {  
                    self::log(0, "child process($this->pid) has processe {$this->currentWorkRequestNum} requests will be exit");  
                    $this->stop();  
                    break;  
                }  
            }  
            exit(0);  
        }  
      
        /** 
         * Collects any children we may have 
         * 
         * @return void 
         */  
        private function collectChildren()  
        {  
            foreach ($this->childrens as $pid => $num) {  
                if (pcntl_waitpid($pid, $status, WNOHANG) > 0) {  
                    unset($this->childrens[$pid]);  
                    $this->workProcessNum++;  
                }  
            }  
        }  
      
        /** 
         * @return void 
         */  
        public function stop()  
        {  
            $this->transport_->close();  
            $this->stop_ = true;  
            foreach ($this->childrens as $pid => $num) {  
                if (!posix_kill($pid, SIGTERM)) {  
                }  
            }  
        }  
      
        /** 
         * 附加信号处理 
         */  
        public static function sig_handler($signo)  
        {  
            switch ($signo) {  
                case SIGTERM:  
                case SIGHUP:  
                case SIGQUIT:  
                case SIGTSTP:  
                    $pid = posix_getpid();  
                    self::log(0, "process($pid) catch signo: $signo");  
                    ThriftServerTMultiProcessServer::$catchQuitSignal = $signo;  
                    break;  
                default:  
            }  
        }  
      
        /** 
         * 附加信号处理 
         */  
        private function registerSignalHandler()  
        {  
            pcntl_signal(SIGTERM, 'ThriftServerTMultiProcessServer::sig_handler');  
            pcntl_signal(SIGHUP, 'ThriftServerTMultiProcessServer::sig_handler');  
            pcntl_signal(SIGQUIT, 'ThriftServerTMultiProcessServer::sig_handler');  
            pcntl_signal(SIGTSTP, 'ThriftServerTMultiProcessServer::sig_handler');  
            declare(ticks=3);  
        }  
      
        /** 
         * 附加守护进程方式 
         */  
        private function daemon()  
        {  
            if (!function_exists('posix_setsid')) {  
                return;  
            }  
            if (($pid1 = pcntl_fork()) != 0) {  
                exit;  
            }  
            posix_setsid();  
            if (($pid2 = pcntl_fork()) != 0) {  
                exit;  
            }  
        }  
      
        public static function log($type, $msg)  
        {  
            static $fds;  
            $msg = date('Y-m-d H:i:s')." $type {$msg}
    ";  
            if (isset(self::$logFiles[$type]) && self::$logFiles[$type]) {  
                if (file_exists(self::$logFiles[$type])) {  
                    if (empty($fds[$type])) {  
                        $fds[$type] = fopen(self::$logFiles[$type], 'a');  
                    }  
                    if (!$fds[$type]) {  
                        $fds[$type] = fopen('php://stdout', 'w');  
                        fwrite($fds[$type], date('Y-m-d H:i:s')." WARNING fopen(".self::$logFiles[$type].") failed
    ");  
                    }  
                } else {  
                    if (!is_dir(dirname(self::$logFiles[$type])) && !mkdir(dirname(self::$logFiles[$type]), 0755, true)) {  
                        $fds[$type] = fopen('php://stdout', 'w');  
                        fwrite($fds[$type], date('Y-m-d H:i:s')." WARNING mkdir(".self::$logFiles[$type].") failed
    ");  
                    } elseif (!($fds[$type] = fopen(self::$logFiles[$type], 'a'))) {  
                        $fds[$type] = fopen('php://stdout', 'w');  
                        fwrite($fds[$type], date('Y-m-d H:i:s')." WARNING fopen(".self::$logFiles[$type].") failed
    ");  
                    }  
                }  
            } else {  
                $fds[$type] = fopen('php://stdout', 'w');  
            }  
            $ret = fwrite($fds[$type], $msg);  
            if (!$ret && self::$logFiles[$type]) {  
                fclose($fds[$type]);  
                $fds[$type] = fopen(self::$logFiles[$type], 'a');  
                $ret = fwrite($fds[$type], $msg);  
            }  
            return true;  
        }  
      
        public static function createPidFile($pid=0)  
        {  
            if (!$pid) {  
                $pid = posix_getpid();  
            }  
            if (file_exists(self::$pidFile)) {  
                $fd = fopen(self::$pidFile, 'w');  
                if (!$fd) {  
                    self::log(1, "fopen(".self::$pidFile.") failed");  
                    return false;  
                }  
            } else {  
                if (!is_dir(dirname(self::$pidFile)) && !mkdir(dirname(self::$pidFile), 0755, true)) {  
                    self::log(1, "mkdir(".self::$pidFile.") failed");  
                    return false;  
                } elseif (!($fd = fopen(self::$pidFile, 'w'))) {  
                    self::log(1, "fopen(".self::$pidFile.") failed");  
                    return false;  
                }  
            }  
            if (!fwrite($fd, "$pid")) {  
                self::log(1, "fwrite(".self::$pidFile.",$pid) failed");  
                return false;  
            }  
            fclose($fd);  
            return  true;  
        }  
    }  

    方案二:方案一固然不错,但是因为没有实践的检验,所以用起来还是有一点担心的。所以,个人建议采用workman的thrift方案,请参考:http://www.workerman.net/workerman-thrift

    1、因为要使用多进程,所以需要先安装pcntl扩展。(安装过程很简单,不是重点,不详细描述过程)

    2、workman-thrift下载解压后,目录中Applications/ThriftRpc/Services存放的自己的服务端服务,即业务接口If、自定义数据类型Type和业务接口的实现。

    3、根目录下的start.php加载并运行了Applications下的各个服务的start.php文件

    4、解压后的目录中Applications/ThriftRpc是一个HelloWorld服务的demo。

    5、现在,看Applications/ThriftRpc/start.php中的关键代码:

    $worker = new ThriftWorker('tcp://0.0.0.0:9090');
    $worker->count = 16;
    $worker->class = 'HelloWorld';

    这里,设置了侦听的IP与端口、设置了服务进程数量与服务的类

    6、查看Applications/ThriftPrc/ThriftWorker.php中的关键代码:

    // 载入该服务下的所有文件
    foreach(glob(THRIFT_ROOT . '/Services/'.$this->class.'/*.php') as $php_file)
    {
        require_once $php_file;
    }
    // 检查类是否存在
    $processor_class_name = "\Services\".$this->class."\".$this->class.'Processor';
    if(!class_exists($processor_class_name))
    {
        ThriftWorker::log("Class $processor_class_name not found" );
        return;
    }
            
    // 检查类是否存在
    $handler_class_name ="\Services\".$this->class."\".$this->class.'Handler';
    if(!class_exists($handler_class_name))
    {
        ThriftWorker::log("Class $handler_class_name not found" );
        return;
    }
           

    根据第5步指定的class,在ThriftWorker中会载入对应路径下的所有php文件进行检查,并检查对应的Processor和Handler类是否存在。最终创建Handler和Processor

    7、运行根目录下的php start.php start,可以看到

    恭喜,服务端运行成功。

    8、关于客户端

    复制 http://www.workerman.net/workerman-thrift 上的客户端代码,即可正常运行。

    <?php  // 引入客户端文件
    require_once __DIR__.'/Applications/ThriftRpc/Clients/ThriftClient.php';
    use ThriftClientThriftClient;
    
    // 传入配置,一般在某统一入口文件中调用一次该配置接口即可
    thriftClient::config(
        array(
            'HelloWorld' => array(
                'addresses' => array(
                    '127.0.0.1:9090',
                    '127.0.0.2:9191',
                ),
                'thrift_protocol' => 'TBinaryProtocol',//不配置默认是TBinaryProtocol,对应服务端HelloWorld.conf配置中的thrift_protocol
                'thrift_transport' => 'TBufferedTransport',//不配置默认是TBufferedTransport,对应服务端HelloWorld.conf配置中的thrift_transport
            ),
            'DInfoCenter' => array(
                'addresses' => array(
                    '127.0.0.1:9090',
                ),
                'thrift_protocol' => 'TBinaryProtocol',//不配置默认是TBinaryProtocol,对应服务端HelloWorld.conf配置中的thrift_protocol
                'thrift_transport' => 'TBufferedTransport',//不配置默认是TBufferedTransport,对应服务端HelloWorld.conf配置中的thrift_transport
            ),
        )
    );
    // =========  以上在WEB入口文件中调用一次即可  ===========
    
    
    // =========  以下是开发过程中的调用示例  ==========
    
    // 初始化一个HelloWorld的实例
    $client = ThriftClient::instance('HelloWorld');
    
    // --------同步调用实例----------
    var_export($client->sayHello('JIM');
    //var_export($client->recv_request("req",strval(time())));
    
    // --------异步调用示例-----------
    /*
    // 异步调用 之 发送请求给服务端(注意:异步发送请求格式统一为 asend_XXX($arg),既在原有方法名前面增加'asend_'前缀)
    $client->asend_sayHello("JERRY");
    $client->asend_sayHello("KID");
    
    // 这里是其它业务逻辑
    sleep(1);
    
    // 异步调用 之 接收服务端的回应(注意:异步接收请求格式统一为 arecv_XXX($arg),既在原有方法名前面增加'arecv_'前缀)
    var_export($client->arecv_sayHello("KID"));
    var_export($client->arecv_sayHello("JERRY"));
    */

    9、截止这里,已经可以成功运行workman-thrift的hello world工程

    10、关于定义自己的服务:

    到这里根据了解,我们可以很容易自己的的服务。比如,我们想定义自己的服务,DInfoCenter,这个过程中有三个一定需要注意的地方:

    第一点:目录名称需要改成DInfoCenter

    第二点:三个文件的namespace声明(第一行),一定要改为:namespace ServicesDInfoCenter;

    第三点:默认生成的DInfoCenter.php中,下面很多类以及函数的调用,都带有命名空间(DInfoCenter),需要把这一段删掉

    到这里,就大致完成了,最后将start.php中的class赋值成DInfoCenter,就全部完成了。

    第一篇无错版的Thrift php教程,到此完成。只要你按上面的步骤,就能实现thrift php的服务端与客户端。

    这是第一篇,但不会是最后一篇关于thrift php的文章,关于服务端使用TMultiplexedProcessor与workman-thrift进行整合,请拭目以待:)

  • 相关阅读:
    豆瓣电台WP7客户端 MVVM重构记录之使用MVVM Light实现Event绑定
    使用DotNetOpenAuth来实现有道云笔记的授权
    豆瓣电台WP7客户端 MVVM重构记录之总结
    使用Npgsql连接Postgres
    WPF自定义一个MessageBox
    字符集其实很简单
    pytest封神之路第六步 断言技巧
    pytest封神之路第七步 用例查找原理
    一文搞懂Cookie,Session,Token,JWT
    典藏版Web功能测试用例库
  • 原文地址:https://www.cnblogs.com/ddcoder/p/7647186.html
Copyright © 2011-2022 走看看