• 简单解析hyperf-TCP-RPC-Json请求的数据结构


    习惯了使用TP框架调用swoft的RPC微服务,使用hyperf框架时,在其文档和百度都没有找到其他框架调用RPC的数据结构,故只能在hyperf的RPC服务端的请求链路进行日志输入和搭建hyperf的PRC客户端进行数据请求。

    主要内容参考hyperf官方文档

    1,搭建hyperf的RPC服务端(192.168.1.212)

    在app目录下新建Rpc文件夹,先新建一个CalculatorServiceInterface接口文件,文件名CalculatorServiceInterface.php

    1. <?php
    2. namespace App\Rpc;
    3. interface CalculatorServiceInterface
    4. {
    5. public function add(int $a, int $b): int;
    6. }

    基于这个Interface,在该目录下添加一个实现方式的CalculatorService,文件名:CalculatorService.php

    1. <?php
    2. namespace App\Rpc;
    3. use Hyperf\RpcServer\Annotation\RpcService;
    4. /**
    5. * 注意,如希望通过服务中心来管理服务,需在注解内增加 publishTo 属性
    6. * @RpcService(name="CalculatorService", protocol="jsonrpc", server="jsonrpc")
    7. */
    8. class CalculatorService implements CalculatorServiceInterface
    9. {
    10. public function add(int $a, int $b) : int
    11. {
    12. return $a +$b;
    13. }
    14. }

    在这里使用了注解方式提供服务,name是服务名称,protocol指定使用了jsonrpc-http协议

    打开config/autoload/server.php,在servers数组下,增加配置

    1. 'servers' => [
    2. [
    3. 'name' => 'http',
    4. 'type' => Server::SERVER_HTTP,
    5. 'host' => '0.0.0.0',
    6. 'port' => 9701,
    7. 'sock_type' => SWOOLE_SOCK_TCP,
    8. 'callbacks' => [
    9. SwooleEvent::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'],
    10. ],
    11. ],
    12. [
    13. 'name' => 'jsonrpc-http',
    14. 'type' => Server::SERVER_HTTP,
    15. 'host' => '0.0.0.0',
    16. 'port' => 9704,
    17. 'sock_type' => SWOOLE_SOCK_TCP,
    18. 'callbacks' => [
    19. SwooleEvent::ON_REQUEST => [Hyperf\JsonRpc\HttpServer::class, 'onRequest'],
    20. ],
    21. ],
    22. // 这里主要用的是这个
    23. [
    24. 'name' => 'jsonrpc',
    25. 'type' => Server::SERVER_BASE,
    26. 'host' => '0.0.0.0',
    27. 'port' => 9705,
    28. 'sock_type' => SWOOLE_SOCK_TCP,
    29. 'callbacks' => [
    30. SwooleEvent::ON_RECEIVE => [\Hyperf\JsonRpc\TcpServer::class, 'onReceive'],
    31. ],
    32. 'settings' => [
    33. 'open_eof_split' => true,
    34. 'package_eof' => "\r\n",
    35. 'package_max_length' => 1024 * 1024 * 2,
    36. ],
    37. ],
    38. ],

     

    2.搭建hyperf的RPC客户端(192.168.1.45)

    同样在app目录下新建Rpc文件夹,先新建一个CalculatorServiceInterface接口文件,文件名CalculatorServiceInterface.php

    1. <?php
    2. namespace App\Rpc;
    3. interface CalculatorServiceInterface
    4. {
    5. public function add(int $a, int $b): int;
    6. }

    修改app/Controllers/IndexController.php

    1. <?php
    2. declare(strict_types=1);
    3. /**
    4. * This file is part of Hyperf.
    5. *
    6. * @link https://www.hyperf.io
    7. * @document https://hyperf.wiki
    8. * @contact group@hyperf.io
    9. * @license https://github.com/hyperf/hyperf/blob/master/LICENSE
    10. */
    11. namespace App\Controller;
    12. use App\Rpc\CalculatorServiceInterface;
    13. use Hyperf\Utils\Context;
    14. use Hyperf\Utils\Coroutine;
    15. use Hyperf\Utils\Parallel;
    16. use Hyperf\Utils\ApplicationContext;
    17. use Hyperf\Di\Annotation\Inject;
    18. use Hyperf\HttpServer\Annotation\AutoController;
    19. class IndexController extends AbstractController
    20. {
    21. public function index()
    22. {
    23. $user = $this->request->input('user', 'Hyperf');
    24. $method = $this->request->getMethod();
    25. return [
    26. 'method' => $method,
    27. 'message' => "Hello22 {$user}.",
    28. ];
    29. }
    30. public function add()
    31. {
    32. $client = ApplicationContext::getContainer()->get(CalculatorServiceInterface::class);
    33. $value = $client->add(10, 20);
    34. return $value;
    35. }
    36. }

    新增客户端路由,修改config\routes.php,增加/add请求链接

    1. <?php
    2. declare(strict_types=1);
    3. /**
    4. * This file is part of Hyperf.
    5. *
    6. * @link https://www.hyperf.io
    7. * @document https://hyperf.wiki
    8. * @contact group@hyperf.io
    9. * @license https://github.com/hyperf/hyperf/blob/master/LICENSE
    10. */
    11. use Hyperf\HttpServer\Router\Router;
    12. Router::addRoute(['GET', 'POST', 'HEAD'], '/', 'App\Controller\IndexController@index');
    13. Router::addRoute(['GET', 'POST', 'HEAD'],'/add', 'App\Controller\IndexController@add');
    14. Router::get('/favicon.ico', function () {
    15. return '';
    16. });

    创建客户端请求服务端的配置文件:config\autoload\services.php

    1. <?php
    2. declare(strict_types=1);
    3. /**
    4. * This file is part of Hyperf.
    5. *
    6. * @link https://www.hyperf.io
    7. * @document https://hyperf.wiki
    8. * @contact group@hyperf.io
    9. * @license https://github.com/hyperf/hyperf/blob/master/LICENSE
    10. */
    11. return [
    12. 'consumers' => [
    13. [
    14. // The service name, this name should as same as with the name of service provider.
    15. 'name' => 'CalculatorService',
    16. // The service registry, if `nodes` is missing below, then you should provide this configs.
    17. // 服务接口名,可选,默认值等于 name 配置的值,如果 name 直接定义为接口类则可忽略此行配置,如 name 为字符串则需要配置 service 对应到接口类
    18. 'service' => \App\Rpc\CalculatorServiceInterface::class,
    19. // 服务提供者的服务协议,可选,默认值为 jsonrpc-http
    20. 'protocol' => 'jsonrpc',
    21. // 负载均衡算法,可选,默认值为 random
    22. 'load_balancer' => 'random',
    23. // 对应容器对象 ID,可选,默认值等于 service 配置的值,用来定义依赖注入的 key
    24. 'id' => \App\Rpc\CalculatorServiceInterface::class,
    25. // If `registry` is missing, then you should provide the nodes configs.
    26. 'nodes' => [
    27. // Provide the host and port of the service provider.
    28. ['host' => '192.168.1.212', 'port' => 9705]
    29. ],
    30. // 配置项,会影响到 Packer 和 Transporter
    31. 'options' => [
    32. 'connect_timeout' => 5.0,
    33. 'recv_timeout' => 5.0,
    34. 'settings' => [
    35. // 根据协议不同,区分配置
    36. 'open_eof_split' => true,
    37. 'package_eof' => "\r\n",
    38. // 'open_length_check' => true,
    39. // 'package_length_type' => 'N',
    40. // 'package_length_offset' => 0,
    41. // 'package_body_offset' => 4,
    42. ],
    43. // 当使用 JsonRpcPoolTransporter 时会用到以下配置
    44. 'pool' => [
    45. 'min_connections' => 1,
    46. 'max_connections' => 32,
    47. 'connect_timeout' => 10.0,
    48. 'wait_timeout' => 3.0,
    49. 'heartbeat' => -1,
    50. 'max_idle_time' => 60.0,
    51. ],
    52. ]
    53. ],
    54. ],
    55. ];

    3.启动服务端和客户端

    热更新启动

    php bin/hyperf.php server:watch

     4.请求服务端地址

    http://192.168.1.45:9701/add

    能输出结构表示没有问题,如果没能正确输出的话,仔细检查配置是否有错误(IP、端口、协议、类名等)

    5.对服务端的RPC解析输出打印

    vendor\hyperf\json-rpc\src\TcpServer.php

    经测试RPC数据对接的方法是buildJsonRpcRequest方法,打印一下数据

     得到数据为:

    {"jsonrpc":"2.0","method":"\/calculator\/add","params":[10,20],"id":"62b6e12b05614","context":[]}

     6.TP框架接入hyperf的PRC接口

    1. $host = 'tcp://192.168.1.212:9705/';
    2. $fp = stream_socket_client($host, $errno, $errstr);
    3. if (!$fp) {
    4. log_write("stream_socket_client fail errno={$errno} errstr={$errstr}", 'RPC');
    5. throw new Exception("stream_socket_client fail errno={$errno} errstr={$errstr}");
    6. }
    7. // hyperf
    8. // {"jsonrpc":"2.0","method":"\/calculator\/add","params":[10,20],"id":"62b6e12b05614","context":[]}
    9. $req = [
    10. "jsonrpc" => '2.0',
    11. "method" => '/calculator/add',
    12. 'params' => [10,20],
    13. 'id' => '',
    14. 'context' => $ext,
    15. ];
    16. $data = json_encode($req) . RPC_EOL;
    17. fwrite($fp, $data);
    18. $result = '';
    19. while (!feof($fp)) {
    20. $tmp = stream_socket_recvfrom($fp, 1024);
    21. if ($pos = strpos($tmp, RPC_EOL)) {
    22. $result .= substr($tmp, 0, $pos);
    23. break;
    24. } else {
    25. $result .= $tmp;
    26. }
    27. }
    28. fclose($fp);
    29. dump($result);

     RPC服务端成功返回数据

    至此,TP框架接入hyperf-PRC-Json就算是完成了,剩下的就是进一步优化请求方式美化代码

  • 相关阅读:
    flurl监听报错返回的信息
    【Java】DDD领域驱动设计理解
    Golang 实现接口和继承
    架构升级实践
    依赖项安全检测新利器:Scorecard API
    深入理解Nginx~Nginx配置的通用语法
    Mac传文件到云服务器
    [持续更新]计算机经典面试题基础篇Day2
    BertTokenizer 使用方法
    【缓存】Spring全家桶中@CacheEvict无效情况共有以下几种
  • 原文地址:https://blog.csdn.net/shark_pang/article/details/125462983