rpc、gRPC快速入门,python调用,protobuf协议

什么是rpc?grpc又是什么?

什么是RPC


远程过程调用协议RPC (Remote Procedure Call Protocol)
RPC是指远程过程调用,也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据
举例:在 a服务内,调用b服务的ticket服务中的get方法,那么在a服务里,直接调用b.ticket.get()来直接调用

客户端在不知道调用细节的情况下,调用存在于远程计算机上的某个对象,就像调用本地应用程序中的对象一样。

什么是grpc


gRPC(Google Remote Procedure Call)是一个高性能、通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf (Protocol Buffers)序列化协议开发,且支持众多开发语言(python,golang,javascript,C,C++、Node.js、Ruby、Objective-C、PHP和C#等)。
gRPC提供了一种简单的方法来精确地定义服务和为iOS、Android和后台支持服务自动生成可靠性很强的客户端功能库。客户端充分利用高级流和链接功能,从而有助于节省带宽、降低的TCP链接次数、节省CPU使用、和电池寿命。

RESTful gRPC
Full Name REpresentational State Transfer Google Remote Procedure Call
Payload Readable Data (typically JSON) Unreadable Binary Data (Protobuf)
HTTP HTTP 1.1/HTTP 2 HTTP/2
Performance Slower Faster
Type Safety No Yes
Cross Language Yes Yes
Client Setup Required Not required
Supported Functions GET/PUT/DELETE/POST/... Any function

// Client端 
//    Student student = Call(ServerAddr, addAge, student)
1. 将这个调用映射为Call ID。
2. 将Call ID,student(params)序列化,以二进制形式打包
3. 把2中得到的数据包发送给ServerAddr,这需要使用网络传输层
4. 等待服务器返回结果
5. 如果服务器调用成功,那么就将结果反序列化,并赋给student,年龄更新

// Server端
1. 在本地维护一个Call ID到函数指针的映射call_id_map,可以用Map<String, Method> callIdMap
2. 等待客户端请求
3. 得到一个请求后,将其数据包反序列化,得到Call ID
4. 通过在callIdMap中查找,得到相应的函数指针
5. 将student(params)反序列化后,在本地调用addAge()函数,得到结果
6. 将student结果序列化后通过网络返回给Client

什么是protobuf


protobuf(Google Protocol Buffers)是Google提供一个具有高效的协议数据交换格式工具库(类似Json),但相比于Json,Protobuf有更高的转化效率,时间效率和空间效率都是JSON的3-5倍
具有跨语言性:python golang java c++ javascript等等等等


生成python客户端和服务器

安装依赖

安装依赖:
pip install grpcio
pip install grpcio-tools
pip install protobuf
转化proto文件成client和server
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. wenet.proto
// 文件名 hello.proto,proto版本
syntax = "proto3";

package hello;

// 定义服务
service Greeter {
  // 发送数据
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// 请求消息,包含用户的姓名。
message HelloRequest {
  string name = 1;
  string age = 2;
  string note=3;
}

// 响应消息,包含问候语。
message HelloReply {
  string message = 1;
}

在命令行输入:

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

gRPC客户端(client.py):

import grpc  # 导入gRPC库
import hello_pb2  # 导入生成的proto文件中的消息类型
import hello_pb2_grpc  # 导入生成的proto文件中的服务类型

def run():
    channel = grpc.insecure_channel('localhost:50051')  # 创建与服务器的通信通道,参数为服务器的地址和端口
    stub = hello_pb2_grpc.GreeterStub(channel)  # 创建与服务器的Stub对象,参数为通信通道
    response = stub.SayHello(hello_pb2.HelloRequest(name='John', age='25', note='Hello gRPC'))  # 调用服务器上的方法,参数为请求消息对象
    print("Response received from server: " + response.message)  # 打印服务器返回的响应消息

if __name__ == '__main__':
    run()  # 运行客户端代码

gRPC服务器(server.py):

import grpc  # 导入gRPC库
from concurrent import futures  # 导入concurrent.futures库,用于多线程处理
import hello_pb2  # 导入生成的proto文件中的消息类型
import hello_pb2_grpc  # 导入生成的proto文件中的服务类型

class GreeterServicer(hello_pb2_grpc.GreeterServicer):
    def SayHello(self, request, context):  # 实现proto文件中定义的方法,参数为请求消息对象和上下文对象
        message = 'Hello, ' + request.name + '! You are ' + request.age + ' years old.'  # 构造响应消息
        return hello_pb2.HelloReply(message=message)  # 返回响应消息对象

def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))  # 创建gRPC服务器对象,参数为线程池的最大工作线程数
    hello_pb2_grpc.add_GreeterServicer_to_server(GreeterServicer(), server)  # 将服务实现添加到服务器中,参数为服务实现对象和服务器对象
    server.add_insecure_port('[::]:50051')  # 指定服务器监听的地址和端口,参数为地址和端口
    server.start()  # 启动服务器
    print("Server started. Listening on port 50051.")  # 打印服务器启动信息
    server.wait_for_termination()  # 等待服务器终止

if __name__ == '__main__':
    serve()  # 运行服务器代码

常用protobuf数据类型和pb文件

常用protobuf数据类型

.proto Type Notes C++ Type Java Type Python Type[2] Go Type Ruby Type
double double double float float64 Float
float float float float float32 Float
int32 使用变长编码,对于负值的效率很低,如果你的域有可能有负值,请使用sint64替代 int32 int int int32 Fixnum 或者 Bignum(根据需要)
uint32 使用变长编码 uint32 int int uint32 Fixnum 或者 Bignum(根据需要)
uint64 使用变长编码 uint64 long int uint64 Bignum
sint32 使用变长编码,这些编码在负值时比int32高效的多 int32 int int int32 Fixnum 或者 Bignum(根据需要)
sint64 使用变长编码,有符号的整型值。编码时比通常的int64高效。 int64 long int int64 Bignum
fixed32 总是4个字节,如果数值总是比总是比228大的话,这个类型会比uint32高效。 uint32 int int uint32 Fixnum 或者 Bignum(根据需要)
fixed64 总是8个字节,如果数值总是比总是比256大的话,这个类型会比uint64高效。 uint64 long int uint64 Bignum
sfixed32 总是4个字节 int32 int int int32 Fixnum 或者 Bignum(根据需要)
sfixed64 总是8个字节 int64 long int int64 Bignum
bool bool boolean bool bool TrueClass/FalseClass
string 一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本。 string String str/unicode string String (UTF-8)
bytes 可能包含任意顺序的字节数据。 string ByteString str/b'' []byte

String (ASCII-8BIT)

repeated 数组(列表) RepeatedField<type> list []type RepeatedField
map 字典 Map<key_type, value_type> dict {} Map

参考资料:grpc-python02--了解rpc与grpc以及创建一个简单的grpc-python_哔哩哔哩_bilibili

gRPC(一)入门:什么是RPC? | Go 技术论坛

https://www.youtube.com/watch?v=gnchfOojMk4

python grpc框架之一 简单示例_51CTO博客_python web 框架

Python gRPC 入门 - 掘金

猜你喜欢

转载自blog.csdn.net/m0_61634551/article/details/131647279