python grpc简单使用

python grpc简单使用

1、rpc和grpc关系

RPC( Remote Procedure Call Protocol),直译来看就是远程过程调用协议

它提供了一套机制,使得应用程序之间可以进行通信,使用时客户端调用server端的接口就像调用本地的函数一样方便。并且server端和client端不限语言,任何语言遵循protobuf协议都可以进行通信。

如下图所示就是一个典型的RPC结构图。

而gRPC是一个开源的RPC框架,建立在HTTP2的基础设施之上,因此具备了HTTP2协议的一系列优势。

  • 二进制分帧的数据传输
  • 多路复用
  • 服务端推送
  • 头部压缩

2、为什么要使用gRPC

有的人可能疑惑,传统的restful API也可以体提供服务接口,同样可以实现接口调用;为什么要用gRPC呢?

是的,gRPC和restful API都提供了一套通信机制,用于server/client模型通信,而且它们都使用http作为底层的传输协议(严格来说gRPC使用的是HTTP2,而restful API不一定)。但是gRPC在以下场景下有着天然优势:

  • 需要对接口进行严格约束的情况,比如我们提供了一个公共的服务,很多人,甚至公司外部的人也可以访问这个服务,这时对于接口我们希望有更加严格的约束,我们不希望客户端给我们传递任意的数据,尤其是考虑到安全性的因素,我们通常需要对接口进行更加严格的约束。这时gRPC就可以通过protobuf来提供严格的接口约束。
  • 对于性能有更高的要求时。有时我们的服务需要传递大量的数据,而又希望不影响我们的性能,这个时候也可以考虑gRPC服务,因为通过protobuf我们可以将数据压缩编码转化为二进制格式,通常传递的数据量要小得多,而且通过http2我们可以实现异步的请求,从而大大提高了通信效率。

3、python使用gRPC示例

3.1、通过protobuf定义接口和数据类型

// example.proto

syntax = "proto3";  // 指明使用proto3语法

option cc_generic_services = true;

service ExampleService {
  rpc SendMessage(Request) returns (Response);   //一个服务中可以定义多个接口,也就是多个函数功能
}

message Request {
  string message = 1; //不是赋值,而是指定唯一编号
}

message Response {
  string reply = 1;
}

3.2、安装相关模块

pip install grpcio
# 安装 python 下的 protoc 编译器
pip install grpcio-tools

3.3、使用 protoc 编译 proto 文件生成接口代码

python -m grpc_tools.protoc -I. proto/example.proto --pythoout=. --grpc_python_out=.
  • -I 指定proto文件输入路径
  • --pythoout= 编译生成处理 protobuf 相关的代码的路径, 这里生成到当前目录
  • --grpc_python_out= 编译生成处理 grpc 相关的代码的路径, 这里生成到当前目录

说明: -I参数后的输入文件路径的上级目录就是 --pythoout 和 --grpc_python_out 的当前路径,也就是.

比如我当前目录结构是这样

如果想要生成的接口代码文件在proto_2文件目录下,怎执行命令

cd grpc_test
python -m grpc_tools.protoc --python_out=. -I. protos_2/test.proto --grpc_python_out=.

执行后:

3.4、编写服务端

# !/usr/bin/env python
# -*- coding: utf-8 -*-

# @FileName: server.py
# @Time    : 2024/4/28  18:03
# @Author  : zcc

import grpc
from concurrent import futures
from protos import example_pb2
from protos import example_pb2_grpc

class ExampleServicer(example_pb2_grpc.ExampleServiceServicer):
    def SendMessage(self, request, context):
        return example_pb2.Response(reply=f"Received: {request.message},我是服务端!")

def run_server():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    example_pb2_grpc.add_ExampleServiceServicer_to_server(ExampleServicer(), server)
    server.add_insecure_port('[::]:50052')
    server.start()
    server.wait_for_termination()

if __name__ == '__main__':
    run_server()

3.5、编写客户端

# !/usr/bin/env python
# -*- coding: utf-8 -*-

# @FileName: client.py
# @Time    : 2024/4/28  17:47
# @Author  : zcc

import grpc
from protos import example_pb2
from protos import example_pb2_grpc

def run_client():
    with grpc.insecure_channel('localhost:50052') as channel:
        stub = example_pb2_grpc.ExampleServiceStub(channel)
        response = stub.SendMessage(example_pb2.Request(message="Hello gRPC!"))
        print(f"Response from server: {response.reply}")

if __name__ == '__main__':
    run_client()

先运行服务端,后运行客户端,就可以看到二者之间的通信了。

posted @ 2024-04-30 11:30  zchang  阅读(10)  评论(0编辑  收藏  举报