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

标量数值类型

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

默认值

python操作的坑

  1. 目录结构

  2. helloworld.proto
  1. syntax = "proto3";
  2. option go_package = "../proto;";
  3. service Greeter {
  4. rpc SayHello (HelloRequest) returns (HelloReply) {}
  5. }
  6. message HelloRequest {
  7. string name = 1;
  8. repeated int32 id = 2;
  9. }
  10. message HelloReply {
  11. string message = 1;
  12. }

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

3. server.py

  1. from concurrent.futures import ThreadPoolExecutor
  2. import grpc
  3. from grpc_hello.proto import helloworld_pb2_grpc, helloworld_pb2
  4. class Greeter(helloworld_pb2_grpc.GreeterServicer):
  5. def SayHello(self, request, context):
  6. return helloworld_pb2.HelloReply(message=f"你好, [name: {request.name}, id: {request.id}]")
  7. if __name__ == '__main__':
  8. # 1. 实例化server
  9. server = grpc.server(ThreadPoolExecutor(max_workers=10))
  10. # 2. 注册逻辑到server中
  11. helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
  12. # 3. 运行server
  13. server.add_insecure_port("127.0.0.1:50051")
  14. server.start()
  15. # 主线程等待所有子线程
  16. server.wait_for_termination()
  1. client.py
  1. import grpc
  2. from grpc_hello.proto import helloworld_pb2, helloworld_pb2_grpc
  3. if __name__ == '__main__':
  4. with grpc.insecure_channel("127.0.0.1:50051") as channel:
  5. greeter = helloworld_pb2_grpc.GreeterStub(channel)
  6. # 方法一:
  7. """
  8. hello_request = helloworld_pb2.HelloRequest(
  9. name="张三",
  10. id=[1, 22, 33],
  11. )
  12. """
  13. # 方法二:
  14. hello_request = helloworld_pb2.HelloRequest()
  15. hello_request.name = "李四"
  16. # 此处就是python操作时的坑所在,不能直接等于,因为创建实例时已经对id初始化了
  17. hello_request.id.extend([11, 22, 33])
  18. hello_request.id.append(44)
  19. rsp: helloworld_pb2.HelloReply = greeter.SayHello(hello_request)
  20. print(rsp.message)

option go_package的作用

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

第一个分号前面的代表生成的pb文件保存的目录路径,第一个分号后面的代表包名称

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

go的客户端和服务端

  1. client.go
点击查看代码
  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "goRPC/grpc_proto_test/proto"
  6. "google.golang.org/grpc"
  7. "log"
  8. )
  9. func main() {
  10. // 创建链接
  11. clientConn, err := grpc.Dial("127.0.0.1:50053", grpc.WithInsecure())
  12. if err != nil {
  13. log.Fatalf("链接失败, %s\n", err.Error())
  14. }
  15. defer clientConn.Close()
  16. // 声明客户端
  17. client := proto.NewGreeterClient(clientConn)
  18. // 客户端调用服务器的方法
  19. helloReplay, _ := client.SayHello(context.Background(), &proto.HelloRequest{
  20. Name: "马亚南",
  21. Url: "mayanan.cn",
  22. })
  23. fmt.Println(helloReplay.Message)
  24. }

2. server.go

点击查看代码
  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "goRPC/grpc_proto_test/proto"
  6. "google.golang.org/grpc"
  7. "log"
  8. "net"
  9. )
  10. type Greeter struct{}
  11. func (g *Greeter) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply, error) {
  12. return &proto.HelloReply{
  13. Message: fmt.Sprintf("hello name: %s, url: %s", request.Name, request.Url),
  14. }, nil
  15. }
  16. func main() {
  17. // 实例化一个server
  18. server := grpc.NewServer()
  19. // 注册逻辑到server中
  20. proto.RegisterGreeterServer(server, &Greeter{})
  21. // 启动server
  22. listener, err := net.Listen("tcp", "127.0.0.1:50053")
  23. if err != nil {
  24. log.Fatalln(err.Error())
  25. }
  26. server.Serve(listener)
  27. }

python的客户端和服务端

  1. client.py
点击查看代码
  1. import grpc
  2. from proto import hello_pb2, hello_pb2_grpc
  3. if __name__ == '__main__':
  4. # 链接server
  5. with grpc.insecure_channel("127.0.0.1:50053") as channel:
  6. greeter = hello_pb2_grpc.GreeterStub(channel)
  7. rsp = greeter.SayHello(hello_pb2.HelloRequest(name="马艳娜", url="https://mayanan.cn"))
  8. print(rsp.message)
  1. server.py
点击查看代码
  1. from concurrent.futures import ThreadPoolExecutor
  2. import grpc
  3. from proto import hello_pb2, hello_pb2_grpc
  4. class Greeter(hello_pb2_grpc.GreeterServicer):
  5. def SayHello(self, request, context):
  6. return hello_pb2.HelloReply(message=f"hello 姓名:{request.name} url: {request.url}")
  7. if __name__ == '__main__':
  8. # 实例化server
  9. server = grpc.server(ThreadPoolExecutor(max_workers=10))
  10. # 注册逻辑到server中
  11. hello_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
  12. # 启动server
  13. server.add_insecure_port("127.0.0.1:50053")
  14. server.start()
  15. server.wait_for_termination()

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

  1. base.proto文件
  1. syntax = "proto3";
  2. message Pong {
  3. string id = 1;
  4. }
  1. hello.proto文件
  1. syntax = "proto3";
  2. import "Lib/site-packages/grpc_tools/_proto/google/protobuf/empty.proto";
  3. import "base.proto";
  4. option go_package = "../proto;proto";
  5. service Greeter {
  6. rpc SayHello(HelloRequest) returns (HelloReply);
  7. rpc Ping(google.protobuf.Empty) returns (Pong);
  8. }
  9. message HelloRequest {
  10. string name = 1;
  11. string url = 2;
  12. }
  13. message HelloReply {
  14. string message = 1;
  15. }

嵌套的message对象

python中的用法

  1. base.proto
  1. syntax = "proto3";
  2. message Pong {
  3. string id = 1;
  4. }
  1. hello.proto文件
点击查看代码
  1. syntax = "proto3";
  2. import "google/protobuf/empty.proto";
  3. import "base.proto";
  4. option go_package = "../proto;proto";
  5. service Greeter {
  6. rpc SayHello(HelloRequest) returns (HelloReply);
  7. rpc Ping(google.protobuf.Empty) returns (Pong);
  8. }
  9. message HelloRequest {
  10. string name = 1;
  11. string url = 2;
  12. }
  13. message HelloReply {
  14. string message = 1;
  15. // 嵌套的message对象
  16. message Result {
  17. string name = 1;
  18. string url = 2;
  19. }
  20. repeated Result data = 2;
  21. }

3. server.py

点击查看代码
  1. from concurrent.futures import ThreadPoolExecutor
  2. import grpc
  3. from proto import hello_pb2, hello_pb2_grpc
  4. from google.protobuf.empty_pb2 import Empty
  5. from proto.base_pb2 import Pong
  6. result = hello_pb2.HelloReply.Result()
  7. pong = hello_pb2.base__pb2.Pong()
  8. empty = hello_pb2.google_dot_protobuf_dot_empty__pb2.Empty()

go中的用法

  1. base.proto
  1. syntax = "proto3";
  2. option go_package = "../proto;proto";
  3. message Empty {}
  4. message Pong {
  5. string id = 1;
  6. }
  1. hello.proto
点击查看代码
  1. syntax = "proto3";
  2. import "base.proto";
  3. option go_package = "../proto;proto";
  4. service Greeter {
  5. rpc SayHello(HelloRequest) returns (HelloReply);
  6. rpc Ping(Empty) returns (Pong);
  7. }
  8. message HelloRequest {
  9. string name = 1;
  10. string url = 2;
  11. }
  12. message HelloReply {
  13. string message = 1;
  14. // 嵌套的message对象
  15. message Result {
  16. string name = 1;
  17. string url = 2;
  18. }
  19. repeated Result data = 2;
  20. }
  1. client.go
  1. result := proto.HelloReply_Result{}
  2. pong := proto.Pong{}
  3. empty := proto.Empty{}
  4. fmt.Println(result, pong, empty)

protobuf中的enum枚举类型

  1. 枚举类型定义
  1. enum Gender {
  2. MALE = 0;
  3. FEMALE = 1;
  4. }
  5. message HelloRequest {
  6. string name = 1;
  7. string url = 2;
  8. Gender g = 3;
  9. }
  1. 枚举类型使用
  1. // 客户端调用服务器的方法
  2. helloReplay, _ := client.SayHello(context.Background(), &proto_bak.HelloRequest{
  3. Name: "马亚南",
  4. Url: "mayanan.cn",
  5. G: proto_bak.Gender_MALE,
  6. })

protobuf中的map类型

  1. map类型的定义
  1. message HelloRequest {
  2. string name = 1;
  3. string url = 2;
  4. Gender g = 3;
  5. map <string, string> mp = 4;
  6. }
  1. map类型的使用
  1. // 客户端调用服务器的方法
  2. helloReplay, _ := client.SayHello(context.Background(), &proto_bak.HelloRequest{
  3. Name: "马亚南",
  4. Url: "mayanan.cn",
  5. G: proto_bak.Gender_MALE,
  6. Mp: map[string]string{"name2": "李四", "age": "28"},
  7. })

protobuf内置的timestamp类型

  1. 将protoc中的include目录复制到当前项目proto_bak目录下,然后导入timestamp.proto文件,定义时间戳类型
点击查看代码
  1. syntax = "proto3";
  2. import "include/google/protobuf/timestamp.proto";
  3. option go_package = "../proto_bak;proto_bak";
  4. service Greeter {
  5. rpc SayHello(HelloRequest) returns (HelloReply);
  6. }
  7. enum Gender {
  8. MALE = 0;
  9. FEMALE = 1;
  10. }
  11. message HelloRequest {
  12. string name = 1;
  13. string url = 2;
  14. Gender g = 3;
  15. map <string, string> mp = 4;
  16. google.protobuf.Timestamp addTime = 5;
  17. }
  18. message HelloReply {
  19. string message = 1;
  20. }
  1. go代码中使用proto中的时间戳类型
点击查看代码
  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "goRPC/grpc_proto_test/proto_bak"
  6. "google.golang.org/grpc"
  7. "google.golang.org/protobuf/types/known/timestamppb"
  8. "log"
  9. "time"
  10. )
  11. func main() {
  12. // 创建链接
  13. clientConn, err := grpc.Dial("127.0.0.1:50053", grpc.WithInsecure())
  14. if err != nil {
  15. log.Fatalf("链接失败, %s\n", err.Error())
  16. }
  17. defer clientConn.Close()
  18. // 声明客户端
  19. client := proto_bak.NewGreeterClient(clientConn)
  20. // 客户端调用服务器的方法
  21. helloReplay, _ := client.SayHello(context.Background(), &proto_bak.HelloRequest{
  22. Name: "马亚南",
  23. Url: "mayanan.cn",
  24. G: proto_bak.Gender_MALE,
  25. Mp: map[string]string{"name2": "李四", "age": "28"},
  26. AddTime: timestamppb.New(time.Now()),
  27. })
  28. fmt.Println(helloReplay.Message)
  29. }

至此,protobuf大致讲解完毕。

protobuf详解的更多相关文章

  1. 通讯协议序列化解读(一) Protobuf详解教程

    前言:说到JSON可能大家很熟悉,是目前应用最广泛的一种序列化格式,它使用起来简单方便,而且拥有超高的可读性.但是在越来越多的应用场景里,JSON冗长的缺点导致它并不是一种最优的选择. 一.常用序列化 ...

  2. grpc系列- protobuf详解

    Protocol Buffers 是一种与语言.平台无关,可扩展的序列化结构化数据的方法,常用于通信协议,数据存储等等.相较于 JSON.XML,它更小.更快.更简单,因此也更受开发人员的青眯. 基本 ...

  3. Protocol Buffers编码详解,例子,图解

    Protocol Buffers编码详解,例子,图解 本文不是让你掌握protobuf的使用,而是以超级细致的例子的方式分析protobuf的编码设计.通过此文你可以了解protobuf的数据压缩能力 ...

  4. Protobuf 文件生成工具 Prototool 命令详解

    Protobuf 文件生成工具 Prototool 命令详解 简介 Prototool 是 Protobuf 文件的生成工具, 目前支持go, php, java, c#, object c 五种语言 ...

  5. ProtoBuf格式详解

    - 数据结构 通过前面的例子,可以看到PB的数据结构就是每项数据独立编码,包含一个表示数据类型 - Varint Varint是一种对数字进行编码的方法,将数字编码成不定长的二进制数据,数值越小,编码 ...

  6. 理论经典:TCP协议的3次握手与4次挥手过程详解

    1.前言 尽管TCP和UDP都使用相同的网络层(IP),TCP却向应用层提供与UDP完全不同的服务.TCP提供一种面向连接的.可靠的字节流服务. 面向连接意味着两个使用TCP的应用(通常是一个客户和一 ...

  7. Protocol Buffer技术详解(Java实例)

    Protocol Buffer技术详解(Java实例) 该篇Blog和上一篇(C++实例)基本相同,只是面向于我们团队中的Java工程师,毕竟我们项目的前端部分是基于Android开发的,而且我们研发 ...

  8. Protocol Buffer技术详解(C++实例)

    Protocol Buffer技术详解(C++实例) 这篇Blog仍然是以Google的官方文档为主线,代码实例则完全取自于我们正在开发的一个Demo项目,通过前一段时间的尝试,感觉这种结合的方式比较 ...

  9. Redis协议详解

    smark Beetle可靠.高性能的.Net Socket Tcp通讯组件 支持flash amf3,protobuf,Silverlight,windows phone Redis协议详解 由于前 ...

随机推荐

  1. SPringBoot 配置类继承WebMvcConfigurationSupport和实现WebMvcConfigurer的使用

    个人习惯使用  实现的方式 public class WebMvcConfiguration implements WebMvcConfigurer {

  2. JS设置网站所有字体变为繁体字

    引入chinese.js var zh_default='n';var zh_choose='t';var zh_expires=7;var zh_class='zh_click';var zh_st ...

  3. 7、滑动窗口套路算法框架——Go语言版

    前情提示:Go语言学习者.本文参考https://labuladong.gitee.io/algo,代码自己参考抒写,若有不妥之处,感谢指正 关于golang算法文章,为了便于下载和整理,都已开源放在 ...

  4. 【LeetCode】163. Missing Ranges 解题报告 (C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 遍历 日期 题目地址:https://leetcode ...

  5. 【LeetCode】529. Minesweeper 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 DFS 日期 题目地址:https://leetco ...

  6. CAS学习笔记一:CAS 授权服务器简易搭建

    什么是CAS CAS是Central Authentication Service的缩写,中央认证服务,一种独立开放指令协议.CAS 是 耶鲁大学(Yale University)发起的一个开源项目, ...

  7. python xlwt写Excel表

    1 xlwt第三方库 说明:xlwt是一个用于将数据和格式化信息写入并生成Excel文件的库. 注意:xlwt不支持写xlsx表,打开表文件报错. 官方文档:https://xlwt.readthed ...

  8. [数据结果]C语言 基础指令汇编

    数据结构 C语言核心操作集合 (1)预定义常量和类型 //函数结果状态代码 #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #d ...

  9. Java程序设计基础笔记 • 【第6章 循环结构进阶】

    全部章节   >>>> 本章目录 6.1 for循环 6.1.1 for循环的简介 6.1.2 for循环的使用 6.1.3 for循环的表达式 6.1.4 实践练习 6.2 ...

  10. unittest_认识unittest(1)

    unittest是python内置的单元测试框架,具备编写用例.组织用例.执行用例.输出报告等自动化框架的条件. 使用unittest前需要了解该框架的五个概念: 即test case,test su ...