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
在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等方法
回到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不能做服务端,然后就弄了个使用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
修改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 = [], $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中注册下
在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);