protobuf详解-01

protobuf的基本类型和默认值,python中的小坑

标量数值类型

标量消息字段可以具有以下类型之一——该表显示了。原型文件,以及自动生成类中的对应类型:

默认值

python操作的坑

  1. 目录结构
  2. helloworld.proto
syntax = "proto3";

option go_package = "../proto;";

service Greeter {
    rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
    string name = 1;
    repeated int32 id = 2;
}

message HelloReply {
    string message = 1;
}

切换到proto目录下,执行命令 python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. helloworld.proto
3. server.py

from concurrent.futures import ThreadPoolExecutor

import grpc

from grpc_hello.proto import helloworld_pb2_grpc, helloworld_pb2


class Greeter(helloworld_pb2_grpc.GreeterServicer):
    def SayHello(self, request, context):
        return helloworld_pb2.HelloReply(message=f"你好, [name: {request.name}, id: {request.id}]")


if __name__ == '__main__':
    # 1. 实例化server
    server = grpc.server(ThreadPoolExecutor(max_workers=10))
    # 2. 注册逻辑到server中
    helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
    # 3. 运行server
    server.add_insecure_port("127.0.0.1:50051")
    server.start()
    # 主线程等待所有子线程
    server.wait_for_termination()

  1. client.py
import grpc

from grpc_hello.proto import helloworld_pb2, helloworld_pb2_grpc

if __name__ == '__main__':
    with grpc.insecure_channel("127.0.0.1:50051") as channel:
        greeter = helloworld_pb2_grpc.GreeterStub(channel)
        # 方法一:
        """
        hello_request = helloworld_pb2.HelloRequest(
            name="张三",
            id=[1, 22, 33],
        )
        """
        # 方法二:
        hello_request = helloworld_pb2.HelloRequest()
        hello_request.name = "李四"
        # 此处就是python操作时的坑所在,不能直接等于,因为创建实例时已经对id初始化了
        hello_request.id.extend([11, 22, 33])
        hello_request.id.append(44)
        rsp: helloworld_pb2.HelloReply = greeter.SayHello(hello_request)

        print(rsp.message)

option go_package的作用

option go_package = "../proto;proto";
第一个分号前面的代表生成的pb文件保存的目录路径,第一个分号后面的代表包名称

当proto文件不同步的时候容易出现的问题

go的客户端和服务端

  1. client.go
点击查看代码
package main

import (
	"context"
	"fmt"
	"goRPC/grpc_proto_test/proto"
	"google.golang.org/grpc"
	"log"

)

func main() {
	// 创建链接
	clientConn, err := grpc.Dial("127.0.0.1:50053", grpc.WithInsecure())
	if err != nil {
		log.Fatalf("链接失败, %s\n", err.Error())
	}
	defer clientConn.Close()
	// 声明客户端
	client := proto.NewGreeterClient(clientConn)
	// 客户端调用服务器的方法
	helloReplay, _ := client.SayHello(context.Background(), &proto.HelloRequest{
		Name: "马亚南",
		Url: "mayanan.cn",
	})

	fmt.Println(helloReplay.Message)
}

2. server.go
点击查看代码
package main

import (
	"context"
	"fmt"
	"goRPC/grpc_proto_test/proto"
	"google.golang.org/grpc"
	"log"
	"net"
)

type Greeter struct{}

func (g *Greeter) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply, error) {
	return &proto.HelloReply{
		Message: fmt.Sprintf("hello name: %s, url: %s", request.Name, request.Url),
	}, nil
}

func main() {
	// 实例化一个server
	server := grpc.NewServer()

	// 注册逻辑到server中
	proto.RegisterGreeterServer(server, &Greeter{})

	// 启动server
	listener, err := net.Listen("tcp", "127.0.0.1:50053")
	if err != nil {
		log.Fatalln(err.Error())
	}
	server.Serve(listener)

}

python的客户端和服务端

  1. client.py
点击查看代码
import grpc

from proto import hello_pb2, hello_pb2_grpc

if __name__ == '__main__':
    # 链接server
    with grpc.insecure_channel("127.0.0.1:50053") as channel:
        greeter = hello_pb2_grpc.GreeterStub(channel)
        rsp = greeter.SayHello(hello_pb2.HelloRequest(name="马艳娜", url="https://mayanan.cn"))

        print(rsp.message)

  1. server.py
点击查看代码
from concurrent.futures import ThreadPoolExecutor

import grpc

from proto import hello_pb2, hello_pb2_grpc


class Greeter(hello_pb2_grpc.GreeterServicer):
    def SayHello(self, request, context):
        return hello_pb2.HelloReply(message=f"hello 姓名:{request.name} url: {request.url}")


if __name__ == '__main__':
    # 实例化server
    server = grpc.server(ThreadPoolExecutor(max_workers=10))

    # 注册逻辑到server中
    hello_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)

    # 启动server
    server.add_insecure_port("127.0.0.1:50053")
    server.start()
    server.wait_for_termination()

proto文件中引入其它的proto文件

  1. base.proto文件
syntax = "proto3";

message Pong {
    string id = 1;
}

  1. hello.proto文件
syntax = "proto3";

import "Lib/site-packages/grpc_tools/_proto/google/protobuf/empty.proto";
import "base.proto";

option go_package = "../proto;proto";

service Greeter {
    rpc SayHello(HelloRequest) returns (HelloReply);
    rpc Ping(google.protobuf.Empty) returns (Pong);
}

message HelloRequest {
    string name = 1;
    string url = 2;
}
message HelloReply {
    string message = 1;
}

嵌套的message对象

python中的用法

  1. base.proto
syntax = "proto3";

message Pong {
    string id = 1;
}

  1. hello.proto文件
点击查看代码
syntax = "proto3";

import "google/protobuf/empty.proto";
import "base.proto";

option go_package = "../proto;proto";

service Greeter {
    rpc SayHello(HelloRequest) returns (HelloReply);
    rpc Ping(google.protobuf.Empty) returns (Pong);
}

message HelloRequest {
    string name = 1;
    string url = 2;
}
message HelloReply {
    string message = 1;

    // 嵌套的message对象
    message Result {
        string name = 1;
        string url = 2;
    }

    repeated Result data = 2;
}

3. server.py
点击查看代码
from concurrent.futures import ThreadPoolExecutor

import grpc

from proto import hello_pb2, hello_pb2_grpc
from google.protobuf.empty_pb2 import Empty
from proto.base_pb2 import Pong

result = hello_pb2.HelloReply.Result()
pong = hello_pb2.base__pb2.Pong()
empty = hello_pb2.google_dot_protobuf_dot_empty__pb2.Empty()

go中的用法

  1. base.proto
syntax = "proto3";
option go_package = "../proto;proto";

message Empty {}
message Pong {
    string id = 1;
}

  1. hello.proto
点击查看代码
syntax = "proto3";

import "base.proto";

option go_package = "../proto;proto";

service Greeter {
    rpc SayHello(HelloRequest) returns (HelloReply);
    rpc Ping(Empty) returns (Pong);
}

message HelloRequest {
    string name = 1;
    string url = 2;
}
message HelloReply {
    string message = 1;

    // 嵌套的message对象
    message Result {
        string name = 1;
        string url = 2;
    }

    repeated Result data = 2;
}

  1. client.go
result := proto.HelloReply_Result{}
pong := proto.Pong{}
empty := proto.Empty{}
fmt.Println(result, pong, empty)

protobuf中的enum枚举类型

  1. 枚举类型定义
enum Gender {
    MALE = 0;
    FEMALE = 1;
}

message HelloRequest {
    string name = 1;
    string url = 2;
    Gender g = 3;
}

  1. 枚举类型使用
	// 客户端调用服务器的方法
	helloReplay, _ := client.SayHello(context.Background(), &proto_bak.HelloRequest{
		Name: "马亚南",
		Url: "mayanan.cn",
		G: proto_bak.Gender_MALE,
	})

protobuf中的map类型

  1. map类型的定义
message HelloRequest {
    string name = 1;
    string url = 2;
    Gender g = 3;
    map <string, string> mp = 4;
}

  1. map类型的使用
	// 客户端调用服务器的方法
	helloReplay, _ := client.SayHello(context.Background(), &proto_bak.HelloRequest{
		Name: "马亚南",
		Url: "mayanan.cn",
		G: proto_bak.Gender_MALE,
		Mp: map[string]string{"name2": "李四", "age": "28"},
	})

protobuf内置的timestamp类型

  1. 将protoc中的include目录复制到当前项目proto_bak目录下,然后导入timestamp.proto文件,定义时间戳类型
点击查看代码
syntax = "proto3";

import "include/google/protobuf/timestamp.proto";

option go_package = "../proto_bak;proto_bak";

service Greeter {
    rpc SayHello(HelloRequest) returns (HelloReply);
}

enum Gender {
    MALE = 0;
    FEMALE = 1;
}

message HelloRequest {
    string name = 1;
    string url = 2;
    Gender g = 3;
    map <string, string> mp = 4;
    google.protobuf.Timestamp addTime = 5;
}

message HelloReply {
    string message = 1;
}

  1. go代码中使用proto中的时间戳类型
点击查看代码
package main

import (
	"context"
	"fmt"
	"goRPC/grpc_proto_test/proto_bak"
	"google.golang.org/grpc"
	"google.golang.org/protobuf/types/known/timestamppb"
	"log"
	"time"
)

func main() {
	// 创建链接
	clientConn, err := grpc.Dial("127.0.0.1:50053", grpc.WithInsecure())
	if err != nil {
		log.Fatalf("链接失败, %s\n", err.Error())
	}
	defer clientConn.Close()
	// 声明客户端
	client := proto_bak.NewGreeterClient(clientConn)
	// 客户端调用服务器的方法
	helloReplay, _ := client.SayHello(context.Background(), &proto_bak.HelloRequest{
		Name:    "马亚南",
		Url:     "mayanan.cn",
		G:       proto_bak.Gender_MALE,
		Mp:      map[string]string{"name2": "李四", "age": "28"},
		AddTime: timestamppb.New(time.Now()),
	})

	fmt.Println(helloReplay.Message)
}

至此,protobuf大致讲解完毕。

posted @ 2022-01-08 18:46  专职  阅读(405)  评论(0编辑  收藏  举报