protobuf 介绍,Python 和 Go 编写 rpc 服务(gRPC) (7)

下面我们来编写 protobuf 文件,它有自己的语法格式,所以相比 json 它的门槛比较高。我们的文件名就叫 matsuri.proto,protobuf 文件的后缀是 .proto。

// syntax 是指定使用哪一种 protobuf 服务, 现在使用的都是 "proto3" syntax = "proto3"; // 包名, 这个不是很重要, 你删掉也是无所谓的 package test; // 编写服务, 每个服务里面有相应的函数(对应 restful 视图函数) // service 表示创建服务 service Matsuri { //使用 rpc 定义函数, 参数名为 matsuri_request, 返回值为 matsuri_response rpc hello_matsuri(matsuri_request) returns (matsuri_response){} } // 所以我们是创建了一个名为 Matsuri 的服务, 服务里面有一个 hello_matsuri 的函数 // 函数接收一个名为 matsuri_request 的参数, 并返回一个 matsuri_response, 至于结尾的 {} 我们后面再说 // 另外参数 matsuri_request、返回值 matsuri_response 是哪里来的呢? 所以我们还要进行定义 // 注意: matsuri_request 虽然是参数, 但我个人更愿意把它称之为参数的载体 // 比如下面定义两个变量 name 和 age, 客户端会把它们放在 matsuri_request 里面, 在服务端中也会通过 matsuri_request 来获取 message matsuri_request { string name = 1; // = 1表示第1个参数 int32 age = 2; } // matsuri_response 同理, 虽然它是返回值, 但我们返回的显然是 result, 只不过需要放在 matsuri_response 里面 // 具体内容在代码中会有体现 message matsuri_response { string result = 1; }

所以有人可能已经发现了,这个 protobuf 文件就是定义一个服务的框架。然后我们就要用这个 protobuf 文件,来生成对应的 Python 服务端和客户端文件。

python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. matsuri.proto

--python_out 和 --grpc_python_out 表示输出路径,. 表示输出到当前路径;-I 表示从哪里寻找 protobuf 文件,这里也是当前目录,matsuri.proto 表示转化的 protobuf 文件。

protobuf 介绍,Python 和 Go 编写 rpc 服务(gRPC)

执行完之后我们看到多出了两个文件,这个是自动帮你生成的,matsuri_pb2.py 是给 protobuf 用的,matsuri_pb2_grpc.py 是给 gRPC 用的。而这两个文件可以用来帮助我们编写服务端和客户端,我们来简单尝试一下,具体细节后面会补充。

# 服务端 # 导入 grpc 第三方库 import grpc # 导入自动生成的两个 py 文件, 还是那句话, matsuri_pb2 是给 protobuf 用的, matsuri_pb2_grpc 是给 grpc 用的 # 这两个文件的名字比较类似, 容易搞混 import matsuri_pb2 as pb2 import matsuri_pb2_grpc as pb2_grpc # 我们在 protobuf 里面创建的服务叫 Matsuri, 所以 pb2_grpc 会给我们提供一个名为 MatsuriServicer 的类 # 我们直接继承它即可, 当然我们这里的类名叫什么就无所谓了 class Matsuri(pb2_grpc.MatsuriServicer): # 我们定义的服务里面有一个 hello_matsuri 的函数 def hello_matsuri(self, matsuri_request, context): """ matsuri_request 就是相应的参数(载体): name、age都在里面 当然我们也可以不叫 matsuri_request, 直接叫 request 也是可以的, 它只是一个变量名 :param request: :param context: :return: """ name = matsuri_request.name age = matsuri_request.age # 里面返回是 matsuri_response, 注意: 必须是这个名字, 因为我们在 protobuf 文件中定义的就是 matsuri_response # 这个 matsuri_response 内部只有一个字符串类型的 result, result 需要放在 matsuri_response 里面 return pb2.matsuri_response(result=f"name is {name}, {age} years old") if __name__ == \'__main__\': # 创建一个 gRPC 服务 # 里面传入一个线程池, 我们这里就启动 4 个线程吧 from concurrent.futures import ThreadPoolExecutor grpc_server = grpc.server(ThreadPoolExecutor(max_workers=4)) # 将我们定义的类的实例对象注册到 gRPC 服务中, 我们看到这些方法的名字都是基于我们定义 protobuf 文件 pb2_grpc.add_MatsuriServicer_to_server(Matsuri(), grpc_server) # 绑定ip和端口 grpc_server.add_insecure_port("127.0.0.1:22222") # 启动服务 grpc_server.start() # 注意: 如果直接这么启动的话, 会发现程序启动之后就会立刻停止 # 因为里面的线程应该是守护线程, 主线程一结束服务就没了 # 所以我们还需要调用一个 wait_fort_termination grpc_server.wait_for_termination()

然后我们启动服务端,会发现可以正常启动。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwfsgj.html