Python 实现 gRPC 与 原始 RPC 的对比:理解 RPC 的基本功能

在分布式系统中,远程过程调用(Remote Procedure Call,RPC) 是一项关键技术,它允许不同计算机之间像调用本地函数一样进行通信。本文通过 Python 代码对比 gRPC 和 原始 RPC(基于 Socket) 来分析 RPC 的基本功能。


1. 什么是 RPC?

RPC(Remote Procedure Call) 是一种允许程序在 不同的进程、机器 之间像调用本地函数一样执行远程函数的技术。本地进程(客户端)调用远程服务器上的方法,服务器执行方法后将结果返回给客户端。

RPC 的核心功能

  1. 客户端-服务器通信:通过网络请求调用远程方法
  2. 序列化与反序列化:将数据转换成可传输格式(JSON、Protobuf)
  3. 自动化传输:隐藏底层通信逻辑,让调用方式更直观
  4. 错误处理:支持异常返回

2. gRPC 与 原始 RPC(基于 Socket) 对比

功能 gRPC 原始 RPC(Socket)
序列化 Protobuf(二进制,高效) JSON(文本格式,易读但体积大)
传输协议 HTTP/2(高性能) 纯 TCP(需手写协议)
代码生成 支持 .proto 自动生成 需手写所有请求/响应逻辑
流式通信 支持(客户端流、服务器流、双向流) 需要手动实现
多语言支持 Python、Go、Java 等 仅限 Python(除非自行实现跨语言支持)
安全性 内置 TLS/SSL 支持 需手动加密
性能 高效、低延迟 较低(TCP+JSON 开销大)

接下来,我们分别实现 gRPC 和 原始 RPC 进行对比。


3. gRPC 实现

gRPC 使用 Protobuf 进行序列化,并自动生成 客户端和服务器端代码

3.1 定义 gRPC 服务

创建 rpc_service.proto

proto 复制代码
syntax = "proto3";

package rpcdemo;

service MathService {
  rpc Add (AddRequest) returns (AddResponse);
}

message AddRequest {
  int32 a = 1;
  int32 b = 2;
}

message AddResponse {
  int32 result = 1;
}

生成 Python 代码:

sh 复制代码
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. rpc_service.proto

3.2 gRPC 服务器

python 复制代码
import grpc
from concurrent import futures
import rpc_service_pb2
import rpc_service_pb2_grpc

class MathService(rpc_service_pb2_grpc.MathServiceServicer):
    def Add(self, request, context):
        return rpc_service_pb2.AddResponse(result=request.a + request.b)

def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    rpc_service_pb2_grpc.add_MathServiceServicer_to_server(MathService(), server)
    server.add_insecure_port('[::]:50051')
    server.start()
    print("gRPC Server started on port 50051")
    server.wait_for_termination()

if __name__ == "__main__":
    serve()

3.3 gRPC 客户端

python 复制代码
import grpc
import rpc_service_pb2
import rpc_service_pb2_grpc

def run():
    channel = grpc.insecure_channel('localhost:50051')
    stub = rpc_service_pb2_grpc.MathServiceStub(channel)
    response = stub.Add(rpc_service_pb2.AddRequest(a=10, b=20))
    print("gRPC Response:", response.result)

if __name__ == "__main__":
    run()

4. 原始 RPC(Socket 实现)

使用 Python 原生 socket 来模拟 RPC 机制。

4.1 原始 RPC 服务器

python 复制代码
import socket
import json

# 定义计算服务
def add(a, b):
    return a + b

# 注册可调用的函数
FUNCTIONS = {
    "add": add
}

def handle_client_connection(client_socket):
    """ 处理客户端请求 """
    try:
        # 接收数据
        data = client_socket.recv(1024).decode('utf-8')
        request = json.loads(data)

        # 获取方法名和参数
        method = request.get("method")
        params = request.get("params", [])

        # 执行方法
        if method in FUNCTIONS:
            result = FUNCTIONS[method](*params)
            response = {"status": "success", "result": result}
        else:
            response = {"status": "error", "message": "Method not found"}

        # 发送响应
        client_socket.send(json.dumps(response).encode('utf-8'))
    except Exception as e:
        response = {"status": "error", "message": str(e)}
        client_socket.send(json.dumps(response).encode('utf-8'))
    finally:
        client_socket.close()

def start_server(host='localhost', port=5000):
    """ 启动RPC服务器 """
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind((host, port))
    server.listen(5)
    print(f"RPC Server listening on {host}:{port}")

    while True:
        client_sock, _ = server.accept()
        handle_client_connection(client_sock)

if __name__ == "__main__":
    start_server()

4.2 原始 RPC 客户端

python 复制代码
import socket
import json

def rpc_call(method, params, host='localhost', port=5000):
    """ 发送 RPC 请求 """
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect((host, port))

    # 构造请求数据
    request = json.dumps({
        "method": method,
        "params": params
    })

    # 发送数据
    client.send(request.encode('utf-8'))

    # 接收响应
    response_data = client.recv(1024).decode('utf-8')
    response = json.loads(response_data)
    
    client.close()
    return response

if __name__ == "__main__":
    result = rpc_call("add", [10, 20])
    print("RPC Response:", result)

5. 总结

5.1 gRPC 与 原始 RPC 的区别

特性 gRPC 原始 RPC(Socket)
序列化方式 Protobuf(高效二进制) JSON(文本格式)
传输协议 HTTP/2 TCP
自动代码生成 支持 (通过 .proto 不支持(需手动实现)
流式传输 支持(双向流、流式响应) 需要手动实现
多语言支持 支持多种语言(Python、Go、Java 等) 仅支持 Python
性能 高效,低延迟 相对较慢(TCP+JSON 有额外开销)

5.2 选择哪种 RPC?

gRPC 适用于:

  • 分布式系统(微服务架构)
  • 多语言通信(前端、后端不同语言)
  • 高性能数据传输(Protobuf + HTTP/2)

原始 RPC(Socket) 适用于:

  • 小型应用(轻量级进程间通信)
  • 学习 RPC 原理
  • 内部服务(单机内进程间通信)

若有错误与不足请指出,关注DPT一起进步吧!!!

相关推荐
冷雨夜中漫步8 小时前
Python快速入门(6)——for/if/while语句
开发语言·经验分享·笔记·python
郝学胜-神的一滴8 小时前
深入解析Python字典的继承关系:从abc模块看设计之美
网络·数据结构·python·程序人生
百锦再8 小时前
Reactive编程入门:Project Reactor 深度指南
前端·javascript·python·react.js·django·前端框架·reactjs
喵手10 小时前
Python爬虫实战:旅游数据采集实战 - 携程&去哪儿酒店机票价格监控完整方案(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·零基础python爬虫教学·采集结果csv导出·旅游数据采集·携程/去哪儿酒店机票价格监控
2501_9449347310 小时前
高职大数据技术专业,CDA和Python认证优先考哪个?
大数据·开发语言·python
helloworldandy10 小时前
使用Pandas进行数据分析:从数据清洗到可视化
jvm·数据库·python
肖永威11 小时前
macOS环境安装/卸载python实践笔记
笔记·python·macos
TechWJ12 小时前
PyPTO编程范式深度解读:让NPU开发像写Python一样简单
开发语言·python·cann·pypto
枷锁—sha12 小时前
【SRC】SQL注入WAF 绕过应对策略(二)
网络·数据库·python·sql·安全·网络安全
abluckyboy12 小时前
Java 实现求 n 的 n^n 次方的最后一位数字
java·python·算法