grpc简单实用 go服务端 php客户端


文章目录

  • 软件
  • 安装
  • 创建proto文件
  • go客户端和服务端
    • 服务端
    • 客户端
  • PHP客户端
    • 安装
    • 生成proto
    • 创建客户端类
    • 调用文件

软件
go 12.7 protobuf 3.8 https://github.com/protocolbuffers/protobuf/releases php7.2 laravel 5.1 composer

安装 任意位置创建文件夹tgrpc
mkdir tgrpc

初始化go mod,包名为tgrpc
go mod init tgrpc

在tgrpc目录下执行包获取,如果下不下来就设置下阿里的代理https://mirrors.aliyun.com/goproxy/
go get google.golang.org/grpc go get github.com/golang/protobuf/proto

下载protobuf,解压后看bin/protoc
创建proto文件 在tgrpc目录下创建person/person.proto文件
syntax = "proto3"; // 生成的文件的包名 package person; // 定义一个单项 RPC服务 service Greeter { // 提供一个添加人员 rpc AddInfo (Person) returns (Status) { } // 获取年龄 rpc GetAge (Name) returns (Status) { } } // Person消息类 message Person { // 类型 字段名 字段标记 string name = 1; int32 age = 2; } message Status { bool status = 1; } message Name { string name = 1; } message Age { int32 age = 1; }

进入person文件夹,执行命令生成person.pb.go
protoc --go_out=plugins=grpc:. person.proto //生成服务端的时候必须使用该段 // protoc --go_out=. person.proto //客户端用的时候这个也行,会少RegisterGreeterServer等方法

go客户端和服务端 服务端 回到tgrpc目录,创建server.go
package main import ( "context" "fmt" "google.golang.org/grpc" "log" "net" "sync" pb "tgrpc/person" ) var person map[string]int32 var lock sync.RWMutex func init() { person = make(map[string]int32) } type gs struct { } func (s gs) AddInfo(c context.Context, p *pb.Person) (*pb.Status, error) { fmt.Println(p.Name, p.Age) lock.Lock() defer lock.Unlock() person[p.Name] = p.Age return &pb.Status{Status: true}, nil } func (s gs) GetAge(c context.Context, name *pb.Name) (*pb.Age, error) { fmt.Println(name.Name) lock.RLock() defer lock.RUnlock() value := person[name.Name] return &pb.Age{Age: value}, nil } func main() { var listener net.Listener var server *grpc.Server var err error if listener, err = net.Listen("tcp", "0.0.0.0:10000"); err != nil { log.Fatalln(err) } server = grpc.NewServer() //注册服务器 // 服务器 GreeterServer类型的数据 //type GreeterServer interface { //// 提供一个添加人员 //AddInfo(context.Context, *Person) (*Status, error) //// 获取年龄 //GetAge(context.Context, *Name) (*Age, error) //} pb.RegisterGreeterServer(server, gs{}) log.Println("服务开启") if err = server.Serve(listener); err != nil { log.Fatalln(err) } }

客户端 回到tgrpc目录,创建client.go
package main import ( "context" "flag" "google.golang.org/grpc" "log" pb "tgrpc/person" ) const ( address= "localhost:50051" defaultName = "world" ) func main() { var conn *grpc.ClientConn var err error var action string var name string var age int var status *pb.Status var pAge *pb.Age //读取参数 flag.StringVar(&action, "action", "get", "方法名") flag.StringVar(&name, "name", "test", "姓名") flag.IntVar(&age, "age", 0, "年龄") flag.Parse() // 创建连接 if conn, err = grpc.Dial("127.0.0.1:10000", grpc.WithInsecure()); err != nil { log.Fatalln(err) } defer conn.Close() // 创建客户端 c := pb.NewGreeterClient(conn) // 添加人 if action == "add" { if status, err = c.AddInfo(context.TODO(), &pb.Person{Name: name, Age: int32(age)}); err != nil { log.Fatalln(err) } else { log.Println(status.Status) } } else { // 获取Age if pAge, err = c.GetAge(context.TODO(), &pb.Name{Name: name}); err != nil { log.Fatalln(err) } else { log.Println(pAge.Age) } } log.Println("end") }

PHP客户端 据说PHP不能做服务端,然后就弄了个使用laravel作为PHP客户端的例子
安装 php grpc的c扩展http://pecl.php.net/package/gRPC
composer安装两个扩展,下不下来的话弄阿里的代理https://developer.aliyun.com/composer
composer require grpc/grpc composer require google/protobuf

生成proto 修改person.proto的package字段,将其改为想要的namespace
例如我想将生成的文件放到namespace App\Services\Grpc\Person下,即项目目录/app/Services/Grpc/Person目录下
package App.Services.Grpc.Person;

运行protoc.exe --php_out=. person.proto,生成两个文件夹App GPBMetadata
当前目录/App/Services/Grpc/Person下的4文件复制到项目目录/app/Services/Grpc/Person目录下
当前目录/GPBMetadata文件夹复制到项目目录/app/Services/Grpc/Person目录下
修改项目目录/app/Services/Grpc/Person/GPBMetadata下Person.php的namespace
namespace GPBMetadata; 改为 namespace App\Services\Grpc\Person\GPBMetadata;

修改项目目录/app/Services/Grpc/Person下的4个文件
将\GPBMetadata替换为\App\Services\Grpc\Person\GPBMetadata

创建客户端类 在项目目录/app/Services/Grpc/Person
_simpleRequest('/person.Greeter/AddInfo', $person, ['\App\Services\Grpc\Person\Status', 'decode'], $metadata, $options); } public function GetAge(\App\Services\Grpc\Person\Name $name, $metadata = https://www.it610.com/article/[], $options = []) { return $this->_simpleRequest('/person.Greeter/GetAge', $name, ['\App\Services\Grpc\Person\Age', 'decode'], $metadata, $options); } }

调用文件
php artisan make:console Tgrpc //创建一个脚本

将Tgrpc.php文件中protected $signature改为
protected $signature = 'grpc:person';

在Kernel中注册下
【grpc简单实用 go服务端 php客户端】在handle中调用
$personService = new \App\Services\Grpc\Person\PersonService("127.0.0.1:10000", [ 'credentials' => \Grpc\ChannelCredentials::createInsecure() ]); $person = new \App\Services\Grpc\Person\Person(); $person->setName("php_name"); $person->setAge(100); list($status, $error) = $personService->AddInfo($person, [])->wait(); var_dump($status->getStatus(), $error); $name = new \App\Services\Grpc\Person\Name(); $name->setName("php_name"); list($age, $error) = $personService->GetAge($name, [])->wait(); var_dump($age->getAge(), $error);

    推荐阅读