在使用之前,必须要安装好相应的grpc与protobuf, 可参考GO与PHP有关grpc,protobuf安装方法
1.使用go mod 创建文件go_grpc_service
https://goproxy.cn : 七牛云赞助支持的开源代理
https://mirrors.aliyun.com/goproxy/ : 阿里云官方维护的go代理
https://goproxy.io/ : 也是一个开源的go代理
go mod init go_grpc_service
set GOPROXY=https://goproxy.io
go mod tidy
go mod download
go mod vendor
2.创建Protobuf文件
在项目里面创建pdfiles目录,在此目录下创建Prod.proto文件,写入下面代码
syntax="proto3"; // 指定proto版本
package services; // 指定默认包名
// 指定golang包名
option go_package = "./;services";
message ProdRequest{
int32 prod_id=1; //传入的商品id
}
message ProdResponse{
int32 prod_stock=1; //商品库存
}
// 定义服务
service ProdService {
rpc SayHello (ProdRequest) returns (ProdResponse) {
}
}
创建services目录(用于生产go文件) 与pdfiles目录同级
在pdfiles目录下执行下面命令(–go_out 输出go格式文件,services:生成的go文件所放在的目录名):
protoc --go_out=plugins=grpc:../services Prod.proto
生成以下文件
go_grpc_service
├── pdfiles
│ └── Prod.proto
├── services
│ ├── Prod.pb.go
在services目录下创建service.go
package services
import "context"
type ProdService struct {
}
func (this ProdService) SayHello(ctx context.Context, req *ProdRequest) (*ProdResponse, error) {
resp := new(ProdResponse)
resp.ProdStock = req.ProdId
return resp, nil
}
go_grpc_service目录下创建main.go
package main
import (
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/grpclog"
"go_grpc_service/services"
"net"
)
func main() {
listen, err := net.Listen("tcp", ":8002")
if err != nil {
grpclog.Fatalf("Failed to listen: %v", err)
}
// 实例化grpc Server
s := grpc.NewServer()
// 注册ProdService
services.RegisterProdServiceServer(s, services.ProdService{
})
fmt.Println("Listen on 8002" )
s.Serve(listen)
}
1.使用go mod 创建文件go_grpc_client
go mod init go_grpc_client
go mod tidy
go mod download
go mod vendor
2.把Prod.pb.go文件拷贝到services目录下
3.go_grpc_client目录下创建main.go
package main
import (
"context"
"fmt"
"go_grpc_client/services"
"google.golang.org/grpc"
"google.golang.org/grpc/grpclog"
)
func main() {
// 连接
conn, err := grpc.Dial("127.0.0.1:8002", grpc.WithInsecure())
if err != nil {
grpclog.Fatalln(err)
}
defer conn.Close()
// 初始化客户端
c := services.NewProdServiceClient(conn)
// 调用方法
//客户端初始化连接后直接调用Prod.pb.go中实现的SayHello方法,即可向服务端发起请求,就像调用本地方法一样。
req := &services.ProdRequest{
ProdId:58}
res, err := c.SayHello(context.Background(), req)
if err != nil {
grpclog.Fatalln(err)
}
fmt.Println(res)
}
创建目录php_grpc_client,把Prod.proto放在该目录中
Prod.proto代码
syntax="proto3"; // 指定proto版本
package services; // 指定默认包名
message ProdRequest{
int32 prod_id=1; //传入的商品id
}
message ProdResponse{
int32 prod_stock=1; //商品库存
}
// 定义服务
service ProdService {
rpc SayHello (ProdRequest) returns (ProdResponse) {
}
}
不带客户端
protoc --proto_path=./ --php_out=./ Prod.proto
生成带客户端的 (grpc_php_plugin 生成带客户端,grpc_php_plugin路径代表安装路径,以通过find / -name grpc_php_plugin 查看)
protoc --proto_path=./ --plugin=protoc-gen-grpc=/usr/local/src/grpc/cmake/build/grpc_php_plugin --php_out=./ --grpc_out=./ Prod.proto
生成以下文件
├── GPBMetadata
│ └── Prod.php
├── Services
│ ├── ProdRequest.php
│ ├── ProdResponse.php
│ ├── ProdServiceClient.php
└── Prod.proto
创建index.php
require_once __DIR__ . '/vendor/autoload.php';
use \Grpc\ChannelCredentials;
use \Services\ProdServiceClient;
use \Services\ProdRequest;
use \Services\ProdResponse;
//127.0.0.1:8002 服务端的端口
$helloClient = new ProdServiceClient('127.0.0.1:8002', [
'credentials' => ChannelCredentials::createInsecure()
]);
$helloRequest = new ProdRequest();
$helloRequest->setProdId(519);
$request = $helloClient->SayHello($helloRequest)->wait();
/** @var HelloReply $response */
list($response, $status) = $request;
var_dump($request);
echo PHP_EOL;
$message = $response->getProdStock();
var_dump($message);
?>
composer.json文件添加以下
"autoload":{
"psr-4":{
"GPBMetadata\\":"GPBMetadata/",
"Services\\":"Services/",
"Grpc\\":"Grpc/"
}
}
修改完 composer.json 的 autoload 字段后需要更新一下 Composer 的自动加载类:
composer dumpautoload -o
执行 php index.php (前提先开启golang的服务)