grpc php客户端与golang服务端通信

版本

go version
go1.19.1 darwin/arm64
protoc --version
libprotoc 3.21.9  

projectpath 代表项目根目录

Go服务端

初始化golang项目,编写proto文件

// projectpath/proto/link.proto

syntax = "proto3";
package proto;
option go_package = "/proto";
service Link{
  rpc  GetLink(GetLinkRequest) returns (GetLinkResponse){}
}

message GetLinkRequest{
  int32 driver = 1;
  string linkId = 2;
  string token = 3;
}

message GetLinkResponse {
  int32 code = 1;
  string link = 2;
  string pwd = 3;
}

安装所需工具

go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28 //用于生成xx.pb.go文件 主要是link.proto里面的message对应的go代码
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2 //用于生成xx_grpc.pb.go 即grpc服务的go版本服务端和客户端

//安装之后查看是否安装成功
protoc-gen-go --version
protoc-gen-go v1.28.1
protoc-gen-go-grpc --version
protoc-gen-go-grpc 1.2.0
如果提示未找到命令的话
export PATH="$PATH:$(go env GOPATH)/bin" //可以加到~/.zshrc 或者 ~/.bashrc文件中

生成grpc服务go相关代码

//在projectpath/proto目录下执行
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative link.proto
//在projectpath/proto下新增了link.pb.go和link_grpc.pb.go文件

编写服务端的的代码

package main

import (
	"context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
	"grpc.demo.com/proto"
	"log"
	"net"
)

func main() {
	lis, err := net.Listen("tcp", "127.0.0.1:50001")
	if err != nil {
		log.Fatalln("listen failed")
	}

	s := grpc.NewServer()
	proto.RegisterLinkServer(s, &Server{})
	reflection.Register(s)
	err = s.Serve(lis)
	if err != nil {
		log.Fatalln("serve failed")
	}
}

type Server struct {
	proto.UnimplementedLinkServer
}

func (s *Server) GetLink(ctx context.Context, req *proto.GetLinkRequest) (*proto.GetLinkResponse, error) {
	return &proto.GetLinkResponse{
		Code: 0,
		Link: "test",
		Pwd:  "none",
	}, nil
}

PHP客户端

工具

要下载很多东西,准备好网络工具

项目外建一个文件夹,cd进去执行

git clone -b v1.45.x --depth=1 https://github.com/grpc/grpc --shallow-submodules --recurse-submodules
cd grpc
mkdir -p cmake/build
cd cmake/build
cmake ../..
make protoc grpc_php_plugin

# cmake 和 make时可能会出现warning,没有error就没问题
echo $(pwd)/grpc_php_plugin //这里就是编译后的grpc-php插件位置

生成php客户端的代码

回到go项目的proto目录下

protoc --php_out=. --grpc_out=. --plugin=protoc-gen-grpc=/Users/bao/Documents/Github/grpc/cmake/build/grpc_php_plugin link.proto

//最终的目录
├── go.mod
├── go.sum
├── proto
   ├── GPBMetadata
      └── Link.php
   ├── Proto
      ├── GetLinkRequest.php
      ├── GetLinkResponse.php
      └── LinkClient.php
   ├── link.pb.go
   ├── link.proto
   └── link_grpc.pb.go
└── server.go

//在proto下会新增GPBMetadata文件夹,生成了Link.php,在proto的Proto文件夹下生成了GetLinkRequest.php,GetLinkResponse.php,LinkClient.php文件,复制到laravel项目的根目录下proto文件夹中
composer 安装 grpc/grpc ^v1.3.0,google/protobuf ^v3.3.0

php调用

项目用的laradock,确保安装了grpc.so,protobuf.so并开启了 ,composer psr-4 自动加载

{
    "autoload": {
        "psr-4": {
            "Proto\\": "proto/",
            "GPBMetadata\\": "proto/",
        }
},
$client      = new LinkClient('host.docker.internal', [
            'credentials' => ChannelCredentials::createInsecure()
        ]);
        $grpcRequest = new GetLinkRequest();
        $grpcRequest->setLinkId("test");
        $grpcRequest->setDriver(12);
        $grpcRequest->setToken("testtoken");
        $resp = $client->GetLink($grpcRequest)->wait();
        dd($resp);

wait返回值为数组,第一个元素可以转换成proto生成的response,这里是GetLinkResponse,第二个是meta信息关联数组,里面code为0时请求成功,其他值为grpc调用失败,需要处理


array:2 [ // app/Http/Controllers/IndexController.php:38
  0 => Proto\GetLinkResponse {#2004 ▼
    #code: 2
    #link: ""
    #pwd: "ocod"
    -desc: Google\Protobuf\Internal\Descriptor {#2042 ▼
      -full_name: "proto.GetLinkResponse"
      -field: array:3 []
      -json_to_field: array:3 []
      -name_to_field: array:3 []
      -index_to_field: array:3 []
      -nested_type: []
      -enum_type: []
      -klass: "Proto\GetLinkResponse"
      -legacy_klass: "Proto\GetLinkResponse"
      -previous_klass: "Proto\GetLinkResponse"
      -options: null
      -oneof_decl: []
      -public_desc: Google\Protobuf\Descriptor {#2043 ▼
        -internal_desc: Google\Protobuf\Internal\Descriptor {#2042}
      }
    }
    -unknown: ""
  }
  1 => {#2034 ▼
    +"metadata": []
    +"code": 0
    +"details": ""
  }
]

如果有端口连通性问题可以用telnet,或者

# Download image
docker pull fullstorydev/grpcurl:latest
# Run the tool
docker run fullstorydev/grpcurl api.grpc.me:443 list