PHP gRPC基础入门指南
原文地址:PHP gRPC基础入门指南
gRPC是一个高性能、开放源码的通用RPC框架。本篇文章分享了如何在PHP语言编程中使用gRPC框架。并展示一个简单的PHP gRPC客户端示例。
PHP中gRPC的基本教程介绍。
通过遍历此示例,您将学习如何:
- 在.proto文件中定义服务。
- 使用协议缓冲区编译器生成客户端代码。
- 使用PHP gRPC API为您的服务编写一个简单的客户端。
它假定对协议缓冲区有一定的了解。请注意,本教程中的示例使用协议缓冲区语言的proto2版本。
还要注意,当前,您只能在PHP中为gRPC服务创建客户端。使用另一种语言创建gRPC服务器。
为什么要使用gRPC?
我们的示例是一个简单的路由映射应用程序,它使客户端可以获取有关其路由功能的信息,创建其路由的摘要以及与服务器和其他客户端交换路由信息(例如流量更新)。
借助gRPC,我们可以在一个.proto
文件中定义一次服务,并以gRPC支持的任何语言生成客户端和服务器,而这又可以在从大型数据中心内的服务器到您自己的平板电脑的各种环境中运行– gRPC为您处理不同的语言和环境。我们还获得了使用协议缓冲区的所有优点,包括有效的序列化,简单的IDL和轻松的接口更新。
示例代码和设置
本教程的示例代码在 /grpc/grpc/tree/v1.33.2/examples/php/route_guide中。要下载示例,请grpc
通过运行以下命令来克隆存储库:
git clone -b v1.33.2 https://github.com/grpc/grpc
您需要grpc-php-plugin来帮助您生成原型文件。您可以从源代码构建它:
cd grpc && git submodule update --init && make grpc_php_plugin
然后将当前目录更改为examples/php/route_guide
并生成原始文件:
cd examples/php/route_guide && ./route_guide_proto_gen.sh
我们的示例是一个简单的路由映射应用程序,它使客户端可以获取有关其路由功能的信息,创建其路由的摘要以及与服务器和其他客户端交换路由信息(例如流量更新)。
您还应该安装相关的工具来生成客户端接口代码(以及用于测试的另一种语言的服务器)。例如,您可以按照这些设置说明获得后者。
试试看!
要尝试示例应用程序,我们需要在本地运行的gRPC服务器。让我们在此存储库中编译并运行例如Node.js服务器:
$ cd ../../node
$ npm install
$ cd dynamic_codegen/route_guide
$ nodejs ./route_guide_server.js --db_path=route_guide_db.json
运行PHP客户端(在另一个终端中):
./run_route_guide_client.sh
下一节将逐步指导您定义此原型服务的方式,如何从中生成客户端库以及如何创建使用该库的客户端存根。
定义服务
首先,让我们看看如何定义所使用的服务。使用协议缓冲区的gRPC服务及其方法请求和响应类型。您可以在下面的示例中看到完整的.proto文件 examples/protos/route_guide.proto
。
要定义服务,请service
在.proto文件中指定一个名称:
service RouteGuide {
...
}
然后,rpc
在服务定义中定义方法,并指定其请求和响应类型。协议缓冲区使您可以定义四种服务方法,所有这些方法都用于RouteGuide
服务中:
1.一个简单的RPC,客户端将请求发送到服务器,然后再接收响应,就像普通的远程过程调用一样。
// Obtains the feature at a given position.
rpc GetFeature(Point) returns (Feature) {}
2.一个响应流RPC,其中客户端向服务器发送一个请求并返回一个响应消息流。您可以通过将stream关键字放在响应类型之前来指定响应流方法。
// Obtains the Features available within the given Rectangle. Results are
// streamed rather than returned at once (e.g. in a response message with a
// repeated field), as the rectangle may cover a large area and contain a
// huge number of features.
rpc ListFeatures(Rectangle) returns (stream Feature) {}
3.一个双向流RPC双方都发送消息序列其他。这两个流是独立运行的,因此客户端和服务器可以按照自己喜欢的顺序进行读写:例如,服务器可以在写响应之前等待接收所有客户端消息,或者可以先读取一条消息再写入一条消息,或其他一些读写组合。每个流中的消息顺序都会保留。您可以通过stream
在请求和响应之前放置关键字来指定这种类型的方法。
// Accepts a stream of RouteNotes sent while a route is being traversed,
// while receiving other RouteNotes (e.g. from other users).
rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
我们的.proto
文件还包含用于服务方法中所有请求和响应类型的协议缓冲区消息类型定义-例如,以下是Point
消息类型:
// Points are represented as latitude-longitude pairs in the E7 representation
// (degrees multiplied by 10**7 and rounded to the nearest integer).
// Latitudes should be in the range +/- 90 degrees and longitude should be in
// the range +/- 180 degrees (inclusive).
message Point {
int32 latitude = 1;
int32 longitude = 2;
}
生成客户端代码
原型文件的PHP客户端存根实现可以通过gRPC PHP Protoc插件生成。编译插件:
make grpc_php_plugin
生成客户端存根实现.php文件:
cd grpc
protoc --proto_path=examples/protos \
--php_out=examples/php/route_guide \
--grpc_out=examples/php/route_guide \
--plugin=protoc-gen-grpc=bins/opt/grpc_php_plugin \
./examples/protos/route_guide.proto
或在grpc/example/php/route_guide
目录下运行帮助程序脚本(如果您通过源代码构建grpc-php-plugin):
./route_guide_proto_gen.sh
目录中将生成许多文件examples/php/route_guide
。您不需要修改这些文件。
要加载这些生成的文件,请将此部分添加到composer.json
目录下的 examples/php
文件中
"autoload": {
"psr-4": {
"": "route_guide/"
}
}
该文件包含:
- 用于填充,序列化和检索我们的请求和响应消息类型的所有协议缓冲区代码。
- 名为的类
Routeguide\RouteGuideClient
,使客户端可以调用RouteGuide
服务中定义的方法。
创建客户端
在本节中,我们将研究为我们的RouteGuide
服务创建一个PHP客户端。您可以在/examples/php/route_guide/route_guide_client.php看到我们完整的示例客户端代码。
构造客户端对象
要调用服务方法,我们首先需要创建一个客户端对象,即所生成RouteGuideClient
类的实例。该类的构造函数期望我们要连接的服务器地址和端口:
$client = new Routeguide\RouteGuideClient('localhost:50051', [
'credentials' => Grpc\ChannelCredentials::createInsecure(),
]);
调用服务方法
简单的RPC
调用简单的RPCGetFeature
与调用本地异步方法几乎一样简单。
$point = new Routeguide\Point();
$point->setLatitude(409146138);
$point->setLongitude(-746188906);
list($feature, $status) = $client->GetFeature($point)->wait();
如您所见,我们创建并填充了一个请求对象,即一个 Routeguide\Point
对象。然后,我们在存根上调用方法,并向其传递请求对象。如果没有错误,那么我们可以从服务器的响应对象(即Routeguide\Feature
对象)中读取响应信息。
print sprintf("Found %s \n at %f, %f\n", $feature->getName(),
$feature->getLocation()->getLatitude() / COORD_FACTOR,
$feature->getLocation()->getLongitude() / COORD_FACTOR);
流式RPC
现在让我们看一下我们的流媒体方法。在这里,我们称为服务器端流方法ListFeatures
,该方法返回geo的流 Feature
:
$lo_point = new Routeguide\Point();
$hi_point = new Routeguide\Point();
$lo_point->setLatitude(400000000);
$lo_point->setLongitude(-750000000);
$hi_point->setLatitude(420000000);
$hi_point->setLongitude(-730000000);
$rectangle = new Routeguide\Rectangle();
$rectangle->setLo($lo_point);
$rectangle->setHi($hi_point);
$call = $client->ListFeatures($rectangle);
// an iterator over the server streaming responses
$features = $call->responses();
foreach ($features as $feature) {
// process each feature
} // the loop will end when the server indicates there is no more responses to be sent.
该$call->responses()
方法调用返回迭代器。当服务器发送响应时,$feature
将在foreach
循环中返回一个对象,直到服务器指示不再有要发送的响应为止。
客户端流方法RecordRoute
类似,不同之处在于,我们$call->write($point)
从客户端调用 要写入的每个点,然后返回a Routeguide\RouteSummary
。
$call = $client->RecordRoute();
for ($i = 0; $i < $num_points; $i++) {
$point = new Routeguide\Point();
$point->setLatitude($lat);
$point->setLongitude($long);
$call->write($point);
}
list($route_summary, $status) = $call->wait();
最后,让我们看一下双向流式RPC routeChat()
。在这种情况下,我们只需将上下文传递给该方法并获取一个BidiStreamingCall
流对象,我们就可以使用该对象来写入和读取消息。
$call = $client->RouteChat();
要编写来自客户端的消息:
foreach ($notes as $n) {
$route_note = new Routeguide\RouteNote();
$call->write($route_note);
}
$call->writesDone();
要从服务器读取消息:
while ($route_note_reply = $call->read()) {
// process $route_note_reply
}
每一方都将始终按照写入的顺序获取另一方的消息,客户端和服务器都可以按照任何顺序读写——流完全独立地运行。
{{ nComment.author.nickname }}
{{ nComment.time }}