PHP laravel+thrift+swoole打造微服务框架
最近研究thrift的时候发现thrift对php之城非常好,那么可不可以使用使用thrift作为rpc框架,使用swoole来实现异步TCP服务,打造一个微服务框架呢。 心动不如行动我们开始尝试一下吧。首先我们创建一个laravel的项目,笔者使用的laravel官方提供的homestead的环境。
安装laravel-s https://github.com/hhxsv5/laravel-s/blob/master/README-CN.md composer require "hhxsv5/laravel-s:~3.5.0" -vvv laravel-s是一个由swoole写的laravel扩展,赋予laravel更好的性能,具体使用方法参看官方文档。 在项目的根目录下新建一个thrift的目录,然后在该子目录下创建 Thrift IDL 文件 user.thrift,用于定义和用户相关的服务接口。 1 namespace php App.Thrift.User 2 // 定义用户接口 3 service User { 4 string getInfo(1:i32 id) 5 } 这里我们定义了一个接口,接着在项目根目录下运行如下命令,根据上述 IDL 文件生成相关的服务代码: thrift -r --gen php:server -out ./ thrift/user.thrift 查看文件这时候我们会发现在AppThriftUser`目录下生成对应的服务代码。 通过 Composer 安装 Thrift PHP 依赖包: composer require apache/thrift 编写服务代码,在 app目录下新建一个 Services/Server 子目录,然后在该目录下创建服务接口类 UserService,该类实现自 `AppThriftUserUserIf` 接口: 1 <?php 2 namespace AppServicesServer; 3 4 5 use AppThriftUserUserIf; 6 7 class UserService implements UserIf 8 { 9 public function getInfo($id) 10 { 11 return "chenSi".$id; 12 } 13 } 在 app 目录下新建一个 Sockets目录用于存放 Swoole 相关代码,首先我们创建一个 ServerTransport.php用来存放服务端代理类,并编写代码如下: 1 <?php 2 namespace AppSockets; 3 4 5 use ThriftServerTServerTransport; 6 7 class ServerTransport extends TServerTransport 8 { 9 /** 10 * @var array 服务器选项 11 */ 12 public $options = [ 13 'dispatch_mode' => 1,//1: 轮循,3: 争抢 14 'open_length_check' => true,//打开包长检测 15 'package_max_length' => 8192000,//最大的请求包长度,8M 16 'package_length_type' => 'N',//长度的类型,参见PHP的pack函数 17 'package_length_offset' => 0,//第N个字节是包长度的值 18 'package_body_offset' => 4,//从第几个字节计算长度 19 ]; 20 21 /** 22 * @var SwooleServer 23 */ 24 public $server; 25 protected $host; 26 protected $port; 27 protected $sockType; 28 29 30 public function __construct($swoole,$host,$port = 9999,$sockType = SWOOLE_SOCK_TCP,$options = []) 31 { 32 $this->server = $swoole; 33 $this->host = $host; 34 $this->port = $port; 35 $this->sockType = $sockType; 36 $this->options = array_merge($this->options,$options); 37 38 } 39 40 41 public function listen() 42 { 43 $this->server =$this->server->addlistener($this->host,$this->port,$this->sockType); 44 $this->server->set($this->options); 45 return null; 46 } 47 48 49 public function close() 50 { 51 //$this->server->shutdown(); 52 return null; 53 } 54 55 56 protected function acceptImpl() 57 { 58 return null; 59 } 60 } 我们在代理类的构造函数中初始化 Swoole TCP 服务器参数,由于我们使用的是laravel-s然后在该类中定义 listen 方法启动这个swoole增加监听的端口并监听客户端请求。 我们在 app/Sockets目录下创建 Transport.php文件用于存放基于 Swoole 的传输层实现代码: 1 <?php 2 /** 3 * Created by PhpStorm. 4 * User: 74100 5 * Date: 2019/10/21 6 * Time: 2:22 7 */ 8 namespace AppSockets; 9 10 use SwooleServer as SwooleServer; 11 use ThriftExceptionTTransportException; 12 use ThriftTransportTTransport; 13 14 class Transport extends TTransport 15 { 16 /** 17 * @var swoole服务器实例 18 */ 19 protected $server; 20 /** 21 * @var int 客户端连接描述符 22 */ 23 protected $fd = -1; 24 /** 25 * @var string 数据 26 */ 27 protected $data = ''; 28 /** 29 * @var int 数据读取指针 30 */ 31 protected $offset = 0; 32 33 /** 34 * SwooleTransport constructor. 35 * @param SwooleServer $server 36 * @param int $fd 37 * @param string $data 38 */ 39 public function __construct(SwooleServer $server,$fd,$data) 40 { 41 $this->server = $server; 42 $this->fd = $fd; 43 $this->data = $data; 44 } 45 46 /** 47 * Whether this transport is open. 48 * 49 * @return boolean true if open 50 */ 51 public function isOpen() 52 { 53 return $this->fd > -1; 54 } 55 56 /** 57 * Open the transport for reading/writing 58 * 59 * @throws TTransportException if cannot open 60 */ 61 public function open() 62 { 63 if ($this->isOpen()) { 64 throw new TTransportException('Swoole Transport already connected.',TTransportException::ALREADY_OPEN); 65 } 66 } 67 68 /** 69 * Close the transport. 70 * @throws TTransportException 71 */ 72 public function close() 73 { 74 if (!$this->isOpen()) { 75 throw new TTransportException('Swoole Transport not open.',TTransportException::NOT_OPEN); 76 } 77 $this->server->close($this->fd,true); 78 $this->fd = -1; 79 } 80 81 /** 82 * Read some data into the array. 83 * 84 * @param int $len How much to read 85 * @return string The data that has been read 86 * @throws TTransportException if cannot read any more data 87 */ 88 public function read($len) 89 { 90 if (strlen($this->data) - $this->offset < $len) { 91 throw new TTransportException('Swoole Transport[' . strlen($this->data) . '] read ' . $len . ' bytes failed.'); 92 } 93 $data = substr($this->data,$this->offset,$len); 94 $this->offset += $len; 95 return $data; 96 } 97 98 /** 99 * Writes the given data out. 100 * 101 * @param string $buf The data to write 102 * @throws TTransportException if writing fails 103 */ 104 public function write($buf) 105 { 106 if (!$this->isOpen()) { 107 throw new TTransportException('Swoole Transport not open.',TTransportException::NOT_OPEN); 108 } 109 $this->server->send($this->fd,$buf); 110 } 111 } Transport类主要用于从传输层写入或读取数据,最后我们创建 Server.php 文件,用于存放基于 Swoole 的 RPC 服务器类: 1 <?php 2 /** 3 * Created by PhpStorm. 4 * User: 74100 5 * Date: 2019/10/21 6 * Time: 2:24 7 */ 8 namespace AppSockets; 9 10 use SwooleServer as SwooleServer; 11 use ThriftServerTServer; 12 13 class Server extends TServer 14 { 15 public function serve() 16 { 17 18 $this->transport_->server->on('receive',[$this,'handleReceive']); 19 $this->transport_->listen(); 20 21 } 22 23 public function stop() 24 { 25 $this->transport_->close(); 26 } 27 28 /** 29 * 处理RPC请求 30 * @param Server $server 31 * @param int $fd 32 * @param int $fromId 33 * @param string $data 34 */ 35 public function handleReceive(SwooleServer $server,$fromId,$data) 36 { 37 $transport = new Transport($server,$data); 38 $inputTransport = $this->inputTransportFactory_->getTransport($transport); 39 $outputTransport = $this->outputTransportFactory_->getTransport($transport); 40 $inputProtocol = $this->inputProtocolFactory_->getProtocol($inputTransport); 41 $outputProtocol = $this->outputProtocolFactory_->getProtocol($outputTransport); 42 $this->processor_->process($inputProtocol,$outputProtocol); 43 } 44 } (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |