Grpc 入门介绍
安装教程
在Golang 下安装
go get google.golang.org/grpc v1.56.1
go get google.golang.org/protobuf v1.30.0
在PHP下安装grpc 扩展
-
使用composer 安装grpc和protobuf(推荐使用)。
{ "name": "root/work", "type": "composer-plugin", "autoload": { "psr-4": { "Root\\Work\\": "src/" } }, "authors": [ { "name": "wangxiaoyang" } ], "require": { "grpc/grpc": "^1.52", "google/protobuf": "^3.23" } }
-
安装php扩展(grpc.so,protobuf.so)
pecl install grpc pecl install protobuf
-
grpc_php_plugin 依赖安装(安装过程较慢)(用于生成客户端代码,可手动写客户端代码)
git clone -b RELEASE_TAG_HERE https://github.com/grpc/grpc cd grpc git submodule update --init mkdir -p cmake/build cd cmake/build cmake ../.. make protoc grpc_php_plugin
安装protobuf 代码编辑器
-
Mac 下推荐使用 brew 安装。安装命令
brew install protobuf
-
Windows 下参考:https://zhuanlan.zhihu.com/p/361997082
-
安装完成后通过命令: protoc 检查是否成功
-
关于对protoc 的使用说明
-
在Golang 下编译命令
protoc --proto_path=. --go_out=. proto/greeter/greeter.proto
-
PHP下编译命令
protoc --proto_path=. --php_out=. proto/greeter/greeter.proto
-
-
搜索参数路径
-
即 -IPATH,--proto_path=PATH ,表示要在哪个文件路径下搜索.proto 文件,既可以用-I 指定,也可以通过--proto_path= 指定路径。
-
当不指定路径时,默认当前路径, 也可以指定多个路径,在多个路径下搜索。
-
如下命令。含义相同
protoc --go_out=. proto/greeter/greeter.proto #点号表示当前路径,注意-I参数没有等于号 protoc -I. --go_out=. proto/greeter/greeter.proto protoc --proto_path=. --go_out=. proto/greeter/greeter.proto
-
-
语言插件路径
-
如: --cpp_out=, php_out= 等,若protoc 内置语言,则无需另外安装。内置语言如下:
-
-
若使用没有内置的语言,则需要单独安装插件。如:golang 的--go_out= , 对应的插件为:protoc-gen-go
-
安装命令如下
# 最新版 go install google.golang.org/protobuf/cmd/protoc-gen-go@latest # 指定版本 go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.3.0
-
-
proto文件位置参数
-
即@<filename> 参数,指定了.proto 的文件具体位置, 如:
/Users/yancy/project/go/src/grpc-client/hello/hello.proto
-
-
Protobuf 语法规范
https://www.topgoer.com/%E5%BE%AE%E6%9C%8D%E5%8A%A1/Protobuf%E8%AF%AD%E6%B3%95.html
Demo
-
编写.proto 文件
syntax = "proto3"; // 指定proto版本 package hello; // 指定默认包名// 指定golang包名 option go_package = "./hello";// 定义Hello服务 service Hello { // 定义SayHello方法 rpc SayHello(HelloRequest) returns (HelloResponse) {} } // HelloRequest 请求结构 message HelloRequest { string name = 1; } // HelloResponse 响应结构 message HelloResponse { string message = 1; int64 code = 2; }
-
在golang下生成go文件
protoc --go_out=./ --go_opt=paths=source_relative --go-grpc_out=./ --go-grpc_opt=paths=source_relative hello.proto
-
生成文件路径
-
编写gRpc服务端代码
// Package server /** package main import ( "context" "fmt" "google.golang.org/grpc" pb "grpc-client/hello" "log" "net" ) const Port = ":50051" type server struct { pb.UnimplementedHelloServer } func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) { log.Printf("Received: %v\n", in.GetName()) return &pb.HelloResponse{Message: "Hello, " + in.GetName()}, nil } func main() { listen, err := net.Listen("tcp", Port) if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() pb.RegisterHelloServer(s, &server{}) fmt.Printf("Starting listen on port: %s", Port) if err := s.Serve(listen); err != nil { log.Fatalf("failed to serve: %v", err) } }
-
编写客户端代码
-
Golang 客户端代码
// Package client /** package main import ( "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/grpclog" pb "grpc-client/hello" "log" ) const ( Addr = "127.0.0.1:50051" ) func main() { conn, err := grpc.Dial(Addr, grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { log.Fatalf("could not greet: %v", err) } defer conn.Close() // 初始化客户端 c := pb.NewHelloClient(conn) // 调用方法 req := &pb.HelloRequest{Name: "gRPC"} res, err := c.SayHello(context.Background(), req) if err != nil { grpclog.Fatalln(err) } log.Printf("Greeting: %s", res.GetMessage()) }
-
PHP 客户端代码
<?php namespace Grpc\Client; use Grpc\BaseStub; use Grpc\Hello\HelloRequest; use Grpc\UnaryCall; class HelloClient extends BaseStub { /** * @throws \Exception */ public function __construct($hostname, $opts, $channel = null) { parent::__construct($hostname, $opts, $channel); } public function sayHello(HelloRequest $argument, $metadata = [], $options = []): UnaryCall { return $this->_simpleRequest('Grpc.Hello.Hello/SayHello', $argument, ['Grpc\Hello\HelloResponse', 'decode'], $metadata, $options); } }
-
-
测试
-
PHP客户端接口测试代码
public function helloRpcAction() { $hostname = "127.0.0.1:50051"; try { $client = new HelloClient($hostname, [ 'credentials' => ChannelCredentials::createInsecure(), ]); $request = new HelloRequest(); $request->setName("phalcon"); list($response, $status) = $client->SayHello($request)->wait(); if ($status->code != STATUS_OK) { ErrorHandler::setErrorInfo($status->code, $status->details); return FALSE; } var_dump($response->getMessage()); var_dump($response->getCode()); var_dump($response->getData()); die; } catch (\Exception $exception) { var_dump($exception->getMessage()); } }
-
启用服务端
-
客户端调用
-
golang客户端调用:
-
php客户端调用:
-
-