protobuf基本语法
https://developers.google.com/protocol-buffers/docs/proto3#enum
python沟通protobuf时会遇到的问题
若想传一个列表类型,在poroto文件中应使用repeated关键字
1 2 3 4
| message HelloRequest { string name = 1; repeated int32 id = 2; }
|
此时在python代码中不能对其直接实例化后直接赋值,而是应使用列表的方法(如:extend,append)等去改变它的值
此外,嵌套定义message也不能实例化后直接赋值
go_package详解
设置:
1
| option go_package = "common/stream/proto/v1";
|
执行:
cd 到目标文件夹
1
| protoc --go_out=plugins=grpc:./ ./hello.proto
|
即使目标文件夹下不存在common/stream/proto/v1也会生成common/stream/proto/v1/hello.pb.go脚本
或者:
设置:
1
| option go_package = "../common/stream/proto/v1";
|
执行命令后会在父路径下生成一系列文件夹及文件
protobuf的一点原理
protobuf不是根据名称来对应的,而是根据编号:
1 2 3 4 5
| message HelloRequest {
string name = 1; repeated int32 id = 2; }
|
假设对方proto文件为:
1 2 3 4 5
| message HelloRequest {
string name = 2; repeated int32 id = 1; }
|
此时会将name映射到id,id映射到name
一个proto文件中引入其它proto文件
应用场景:有一些常用的service与message可能很多proto文件都要用到,这时不妨将这些service与message放到一个公用的proto文件中,在需要调用时import。
1 2 3 4 5 6 7 8 9 10
| syntax = "proto3";
message Empty{ }
message Pong{ string id = 1; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| syntax = "proto3"; import "python_grpc_helloworld/proto/base.proto";
service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} rpc Ping (Empty) returns (Pong) {} }
message HelloRequest { string name = 1; }
message HelloReply { string message = 1; }
|
message对象嵌套
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| syntax = "proto3";
service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} }
message HelloRequest { string name = 1; }
message HelloReply { string message = 1;
message Result { string name = 1; string age = 2; } repeated Result persons = 2; }
|
python下使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import grpc from concurrent import futures from proto import hello_pb2,hello_pb2_grpc
class Greeter(hello_pb2_grpc.GreeterServicer):
def SayHello(self, request, context): names = ["name1", "name2", "name3"] results = [] for name in names: result = hello_pb2.HelloReply.Result(name=name,age="17") results.append(result) return hello_pb2.HelloReply(message=f"hello,{request.name}",persons=results)
if __name__ == "__main__": server = grpc.server(futures.ThreadPoolExecutor(5)) hello_pb2_grpc.add_GreeterServicer_to_server(servicer=Greeter(),server=server) server.add_insecure_port('127.0.0.1:50000') server.start() server.wait_for_termination()
|
1 2 3 4 5 6 7 8
| import grpc from python_grpc_helloworld.proto import hello_pb2_grpc,hello_pb2
with grpc.insecure_channel('127.0.0.1:50000') as channel: stub = hello_pb2_grpc.GreeterStub(channel) rsp: hello_pb2.HelloReply = stub.SayHello(hello_pb2.HelloRequest(name="lily"))
print(rsp.persons)
|
go下使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| package main
import ( "context" "net"
"google.golang.org/grpc"
"awesomeProject/grpc_test/proto" )
type Server struct{}
func (s *Server) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply,error){ var results []*proto.HelloReply_Result for i:=0;i<10;i++{ result := proto.HelloReply_Result{ Name: "name", Age: string(i), } results = append(results,&result) } return &proto.HelloReply{ Message: "Hello" + request.Name, Persons: results, },nil }
func main(){ server := grpc.NewServer() proto.RegisterGreeterServer(server,&Server{}) listen,err := net.Listen("tcp","127.0.0.1:50000") if err != nil{ panic("fail to listen:" + err.Error()) } err = server.Serve(listen) if err != nil{ panic("fail to start:" + err.Error()) } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package main
import ( "awesomeProject/grpc_test/proto" "context" "fmt" "google.golang.org/grpc" )
func main(){ conn, err := grpc.Dial("127.0.0.1:50000", grpc.WithInsecure()) if err != nil{ panic(err) } defer conn.Close()
c := proto.NewGreeterClient(conn) resp, err := c.SayHello(context.Background(), &proto.HelloRequest{Name:"Lily"}) if err != nil{ panic(err) } fmt.Println(resp.Persons) }
|
几种类型
枚举
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| syntax = "proto3";
option go_package = "./;proto";
service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} }
message HelloRequest { string name = 1; }
message HelloReply { string message = 1;
message Result { string name = 1; string age = 2; } repeated Result persons = 2;
enum Gender{ MALE = 0; FEMALE = 1; }
Gender g = 3; }
|
生成的相关代码
1 2 3 4 5 6
| type HelloReply_Gender int32
const ( HelloReply_MALE HelloReply_Gender = 0 HelloReply_FEMALE HelloReply_Gender = 1 )
|
map
不建议使用,message本身很像map
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| syntax = "proto3";
option go_package = "./;proto";
service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} }
message HelloRequest { string name = 1; }
message HelloReply { string message = 1;
message Result { string name = 1; string age = 2; } repeated Result persons = 2;
enum Gender{ MALE = 0; FEMALE = 1; } Gender g = 3;
map<string ,string >mp = 4; }
|
1 2 3 4 5 6 7
| return &proto.HelloReply{ Message: "Hello" + request.Name, Persons: results, G: proto.HelloReply_FEMALE, Mp: map[string]string{"hhh":"2333","QAQ":"QWQ"}, },nil
|