gRPC的官方文档中虽然没有给出PHP做Server的例子,但实际上grpc的扩展是支持的。
参考扩展中提供的几个类以及扩展内部的一些代码,写了一个简单的示例
这个示例只是证明PHP可以直接写gRPC服务,不代表可以在生产环境中这么用。主要原因有这么几点:
- 不借助pcntl或swoole的话是个单进程的服务,并发会阻塞
- 没做性能测试以及是否有内存泄漏的测试
- 而且直接PHP做Server的争议也比较大
完整示例代码(https://github.com/ssfyn/php-grpc-server-example)
Server端的主要逻辑:
$this->server = new \Grpc\Server([]);
$this->server->addHttp2Port('0.0.0.0:50051');
$this->server->start();
while($request = $this->server->requestCall()){
$method = $request->method;
$call = $request->call;
if ($method=='/dev.fyn.HelloWorld/SayHello') {
//接收请求
$recv = $call->startBatch([
\Grpc\OP_RECV_MESSAGE => true
]);
//将请求的数据转换为对象
$request = new SayHelloRequest();
$request->mergeFromString($recv->message);
//调用业务代码
$impl = new HelloWorldImpl();
$response = $impl->sayHello($request);
//处理返回值,即使没有metadata也要设置OP_SEND_INITIAL_METADATA,不然会一直阻塞在这里
$call->startBatch([
\Grpc\OP_SEND_INITIAL_METADATA => [],
\Grpc\OP_SEND_MESSAGE => [
'message'=>$response->serializeToString()
],
\Grpc\OP_SEND_STATUS_FROM_SERVER => [
'code'=>\Grpc\STATUS_OK,
'details'=>'OK'
],
]);
} else {
$call->startBatch([
\Grpc\OP_SEND_INITIAL_METADATA => [],
\Grpc\OP_SEND_STATUS_FROM_SERVER => ['code'=>\Grpc\STATUS_NOT_FOUND,'details'=>'Not found'],
]);
}
}