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 }
(编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
