简陋的RPC

使用Socket实现客户端,服务端,通信

1.客户端。调用"远程"的add(a,b)方法,就像调用本地方法一样。

  1. 服务端。在另一个进程里,真正实现这个add方法。

  2. 通信:设计一个简陋的协议,调用TCP Socket传输调用信息和结果】

通信

python 复制代码
# common.py
# 这个文件定义了客户端和服务端都知道的"约定"(这就是API接口!)

# 这是我们想要远程调用的方法名
METHOD_ADD = "add"

# 这是我们自己设计的极其简单的"协议"
# 客户端发送的请求格式: method_name,arg1,arg2,...(用逗号分隔的字符串)
# 例如: "add,3,5"
# 服务端返回的响应格式: 直接返回结果,如 "8"

服务端

服务端监听端口,收到请求后,解析协议,调用本地方法,返回结果。服务端监听端口,收到请求后,解析协议,调用本地方法,返回结果。

python 复制代码
# server.py
import socket
from common import METHOD_ADD

# 1. 真正实现"远程"方法(服务端本地的函数)
def add(a, b):
    """这就是服务端真正要执行的函数"""
    return a + b

def run_server(host='localhost', port=9999):
    # 2. 创建一个TCP Socket(搞个座机)
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_socket.bind((host, port)) # 告诉座机电话号码
    server_socket.listen(5) # 开始接听,最多5个排队
    print(f"✅ RPC 服务端启动在 {host}:{port},等待调用...")

    # 3. 死循环,一直处理客户端打来的电话
    while True:
        client_socket, addr = server_socket.accept() # 接电话
        print(f"📞 来自 {addr} 的连接")
        
        # 4. 读取客户端发来的请求(对方在电话里说的话)
        request_data = client_socket.recv(1024).decode('utf-8').strip()
        if not request_data:
            continue
        
        print(f"📨 收到原始请求: {request_data}")
        
        # 5. 【解析协议】按照我们的约定,解析对方的话
        parts = request_data.split(',')
        method_name = parts[0]
        args = parts[1:]
        
        result = None
        # 6. 根据方法名,调用本地对应的函数
        if method_name == METHOD_ADD:
            if len(args) == 2:
                a, b = int(args[0]), int(args[1])
                result = add(a, b) # 真正调用本地函数!
            else:
                result = "Error: add方法需要2个参数"
        else:
            result = f"Error: 未知方法 {method_name}"
        
        # 7. 把函数执行结果返回给客户端
        print(f"📤 返回结果: {result}")
        client_socket.sendall(f"{result}".encode('utf-8'))
        
        # 8. 挂电话
        client_socket.close()

if __name__ == '__main__':
    run_server()

客户端

python 复制代码
# client.py
import socket
from common import METHOD_ADD

class SimpleRPCClient:
    def __init__(self, host='localhost', port=9999):
        self.host = host
        self.port = port

    def call(self, method_name, *args):
        """真正的远程调用核心方法"""
        # 1. 建立到服务端的TCP连接(拨号)
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect((self.host, self.port))
        
        # 2. 【封装协议】按照我们的约定,组装请求消息
        # 格式: "method_name,arg1,arg2,..."
        request_data = f"{method_name},{','.join(str(arg) for arg in args)}"
        
        # 3. 发送请求(对着电话说话)
        print(f"📤 发送请求: {request_data}")
        sock.sendall(request_data.encode('utf-8'))
        
        # 4. 等待并接收服务端的响应(听对方回复)
        response_data = sock.recv(1024).decode('utf-8')
        print(f"📨 收到响应: {response_data}")
        
        # 5. 关闭连接(挂电话)
        sock.close()
        
        # 6. 返回结果
        return response_data

# 提供一个"本地方法"一样的假象
def add(a, b):
    """客户端版本的add方法,它内部是远程调用"""
    client = SimpleRPCClient()
    result = client.call(METHOD_ADD, a, b)
    return int(result) # 将字符串响应转换为整数

if __name__ == '__main__':
    # 使用方式1:直接使用底层call方法
    print("=== 方式1: 直接调用call方法 ===")
    client = SimpleRPCClient()
    result = client.call(METHOD_ADD, 3, 5)
    print(f"计算结果: {result}\n")
    
    # 使用方式2:调用包装好的函数,像本地方法一样!
    print("=== 方式2: 调用像本地方法一样的函数 ===")
    sum_result = add(10, 20)
    print(f"计算结果: {sum_result}")
bash 复制代码
✅ RPC 服务端启动在 localhost:9999,等待调用...
📞 来自 ('127.0.0.1', 54437) 的连接
📨 收到原始请求: add,3,5
📤 返回结果: 8
📞 来自 ('127.0.0.1', 54438) 的连接
📨 收到原始请求: add,10,20
📤 返回结果: 30
python 复制代码
=== 方式1: 直接调用call方法 ===
📤 发送请求: add,3,5
📨 收到响应: 8
计算结果: 8

=== 方式2: 调用像本地方法一样的函数 ===
📤 发送请求: add,10,20
📨 收到响应: 30
计算结果: 30

总结

  1. RPC的本质:客户端代理+网络传输+服务端分发。客户端调用的add函数根本不在本地,而是通过网络告诉服务端"帮我执行一个add函数",然后把结果给我

2.协议的作用:客户端和服务端必须有一个共同的约定(Protocol),才知道怎么打包和解析数据。这里用的是简单的逗号分隔字符串。现实中用的是Protobuf,Thrift等更高效的协议。

  1. TCP的作用:提供了可靠的、双向的字节流通道。这里的"协议"字符串就是通过这个通道传输的

  2. 框架的作用:Dubbo、gRPC就是把这个过程抽象化、优化。它们帮自动生成代理、管理连接池、处理序列化、负责服务器发现。让你用一行@Reference就搞定一切。

相关推荐
天诰7 小时前
SA-K-11 检索会消失吗与四个未解问题
java·服务器·人工智能·python·机器学习·ai编程
陈希1239 小时前
Linux 防火墙配置实战:firewalld、iptables 与云安全组
linux·运维·服务器
女神下凡10 小时前
芯参谋(95):嵌入式文件系统_开发指南
linux·服务器·arm开发·驱动开发·设计规范
@兽血沸腾10 小时前
Windows系统安装Jenkins部署应用至远程Windows服务器操作指南
运维·服务器·jenkins
承渊政道13 小时前
Linux网络学习【Reactor反应堆模式】
linux·网络·学习·ubuntu·reactor
讯捷蓝达15 小时前
戴尔R720xd服务器卡死在 “Configuring Memory...Done“,换了内存还是卡?问题根本不在内存
运维·服务器
数字新视界18 小时前
动环监控信创适配在智能机房管理中的应用价值与未来展望
大数据·服务器·数据库·动环监控系统·动力与环境监控系统
爱和冰阔落18 小时前
【Linux网络】TCP 服务器如何并发处理多个客户端?从 fork、僵尸进程到双重 fork
linux·运维·服务器·网络
lisanmengmeng18 小时前
alertmanger 标签 rules 打上分组标签
linux·运维·服务器
严肃小白兔19 小时前
Cloudflare 更新 API Token 管理:从最小权限到自动化凭据安全
网络·安全·自动化