/** * 获取一个实例 * @return instance */ protected function __instance() { if (\Thrift\Context::get('serverName') != $this->serviceName) { \Thrift\Context::put('serverName', $this->serviceName); } $address = CLientForTest::getOneAddress($this->serviceName); list($ip, $port) = explode(':', $address); $socket = new \Thrift\Transport\TSocket($ip, $port); // 接收超时 if (($timeout = \Thrift\Context::get('timeout')) && $timeout >= 1) { $socket->setRecvTimeout($timeout * 1000); } else { // 默认30秒 $socket->setRecvTimeout(30000); } $transport = new \Thrift\Transport\TFramedTransport($socket); $pname = \Thrift\Context::get('protocol') ? \Thrift\Context::get('protocol') : 'binary'; $protocolName = self::getProtocol($pname); $protocol = new $protocolName($transport); $classname = '\\Provider\\' . $this->serviceName . "\\" . $this->serviceName . "Client"; if (!class_exists($classname)) { $this->includeFile($classname); } try { $transport->open(); } catch (\Exception $e) { CLientForTest::kickAddress($address); throw $e; } return new $classname($protocol); }
/** * 业务处理(non-PHPdoc) * @see PHPServerWorker::dealProcess() */ public function dealProcess($recv_str) { // 拷贝一份数据包,用来记录日志 $recv_str_copy = $recv_str; // 统计监控记录请求开始时间点,后面用来统计请求耗时 StatisticHelper::tick(); // 清除上下文信息 \Thrift\Context::clear(); // 服务名 $serviceName = $this->serviceName; // 本地调用方法名 $method_name = 'none'; // 来源ip $source_ip = $this->getRemoteIp(); // 尝试读取上下文信息 try { // 去掉TFrameTransport头 $body_str = substr($recv_str, 4); // 读上下文,并且把上下文数据从数据包中去掉 \Thrift\ContextReader::read($body_str); // 再组合成TFrameTransport报文 $recv_str = pack('N', strlen($body_str)) . $body_str; // 如果是心跳包 if (\Thrift\Context::get('isHeartBeat') == 'true') { $thriftsocket = new \Thrift\Transport\TBufferSocket(); $thriftsocket->setHandle($this->connections[$this->currentDealFd]); $thriftsocket->setBuffer($recv_str); $framedTrans = new \Thrift\Transport\TFramedTransport($thriftsocket); $protocol = new Thrift\Protocol\TBinaryProtocol($framedTrans, false, false); $protocol->writeMessageBegin('#$%Heartbeat', 2, 0); $protocol->writeMessageEnd(); $protocol->getTransport()->flush(); return; } } catch (Exception $e) { // 将异常信息发给客户端 $this->writeExceptionToClient($method_name, $e, self::getProtocol(\Thrift\Context::get('protocol'))); // 统计上报 StatisticHelper::report($serviceName, $method_name, $source_ip, $e, $recv_str_copy); return; } // 客户端有传递超时参数 if (($timeout = \Thrift\Context::get("timeout")) && $timeout >= 1) { pcntl_alarm($timeout); } // 客户端有传递服务名 if (\Thrift\Context::get('serverName')) { $serviceName = \Thrift\Context::get('serverName'); } // 尝试处理业务逻辑 try { // 服务名为空 if (!$serviceName) { throw new \Exception('Context[serverName] empty', 400); } // 如果handler命名空间为provider if ($this->handlerNamespace == 'Provider') { $handlerClass = $this->handlerNamespace . '\\' . $serviceName . '\\' . $serviceName . 'Handler'; } else { $handlerClass = $this->handlerNamespace . '\\' . $serviceName; } // processor $processorClass = $this->providerNamespace . '\\' . $serviceName . '\\' . $serviceName . 'Processor'; // 文件不存在尝试从磁盘上读取 if (!class_exists($handlerClass, false)) { clearstatcache(); if (!class_exists($processorClass, false)) { require_once $this->providerDir . '/' . $serviceName . '/Types.php'; require_once $this->providerDir . '/' . $serviceName . '/' . $serviceName . '.php'; } $handler_file = $this->handlerNamespace == 'Provider' ? $this->handlerDir . '/' . $serviceName . '/' . $serviceName . 'Handler.php' : $this->handlerDir . '/' . $serviceName . '.php'; if (is_file($handler_file)) { require_once $handler_file; } if (!class_exists($handlerClass)) { throw new \Exception('Class ' . $handlerClass . ' not found', 404); } } // 运行thrift $handler = new $handlerClass(); $processor = new $processorClass($handler); $pname = \Thrift\Context::get('protocol') ? \Thrift\Context::get('protocol') : 'binary'; $protocolName = self::getProtocol($pname); $thriftsocket = new \Thrift\Transport\TBufferSocket(); $thriftsocket->setHandle($this->connections[$this->currentDealFd]); $thriftsocket->setBuffer($recv_str); $framedTrans = new \Thrift\Transport\TFramedTransport($thriftsocket, true, true); $protocol = new $protocolName($framedTrans, false, false); $protocol->setTransport($framedTrans); // 请求开始时执行的函数,on_request_start一般在bootstrap初始化 if (function_exists('on_phpserver_request_start')) { \on_phpserver_request_start(); } $processor->process($protocol, $protocol); // 请求结束时执行的函数,on_request_start一般在bootstrap中初始化 if (function_exists('on_phpserver_request_finish')) { // 这里一般是关闭数据库链接等操作 \on_phpserver_request_finish(); } $method_name = $protocol->fname; } catch (Exception $e) { // 异常信息返回给客户端 $method_name = !empty($protocol->fname) ? $protocol->fname : 'none'; $this->writeExceptionToClient($method_name, $e, !empty($protocolName) ? $protocolName : 'Thrift\\Protocol\\TBinaryProtocol'); StatisticHelper::report($serviceName, $method_name, $source_ip, $e, $recv_str_copy); return; } // 统计上报 StatisticHelper::report($serviceName, $method_name, $source_ip); }