一个简单RPC框架是如何炼成的(V)——引入传输层

开局篇我们说了,RPC框架的四个核心内容

  1. RPC数据的传输
  2. RPC消息 协议
  3. RPC服务注册
  4. RPC消息处理   
接下来处理数据传输。实际应用场景一般都是基于socket。socket代码比较多,使用起来也比较麻烦。而且具体的传输通道使用socket或者其他的方式,如更上层的http,或者android里的binder,都是可替换的,只是具体的一种实现而已。所以,这里我就偷个懒,只是引入一个很简单的Connection类,用来描述一下如何将数据传输 这一层给独立出来。

首先简单列出Connection类的实现,很简单,就是两个list,一个管发送,一个管接收。(实现没有考虑多线程安全,实际是必须考虑的)。
需要说明的是,这里的recv的实现约定是阻塞式的,也就是如果没有收到任何数据,recv调用会一直阻塞。
class Connection(object):
    '''
    @RPC 连接。一般说来,都是socket连接,这里简化起见,直接本地变量实现。
    '''


    def __init__(self, sending_msg_list, recving_msg_list):
        '''
        Constructor
        '''
        self.sending_msg_list = sending_msg_list
        self.recving_msg_list = recving_msg_list
    
    def send(self, message):
        self.sending_msg_list.append(message)
    
    def recv(self):
        while len(self.recving_msg_list) == 0: time.sleep(0.01)
        return self.recving_msg_list.pop(0)
    
    def isClosed(self):
        return False


有了这个connection,剩下的就只要将rpc消息统统通过这个connection去发送,通过这个Connection去接收。

接着修改客户端的request请求,不再直接调用server端的procRequest方法,而是将请求交给connection,去发送。  然后等待connection收到server端的回复,将回复消息从connection中取出来。
def request(self, req):
        # 全部简化处理,不考虑线程安全问题,不考虑异步
        # 先是将RPC消息发送到服务端,然后服务端就会处理,并将结果发回到客户端,客户端这边接收处理结果。
        # self.remote.procRequest(req) // 删除
        self.conn.send(req)
        rsp = self.conn.recv()
        return rsp.result

同样的,修改服务端收到request请求后的处理。首先反复调用connection.recv()方法读取客户端发过来的请求。当请求处理完成后,不再直接以函数返回的方式return,而是将rsp交给connection,由connection负责传输给client
    # def procRequest(self, req): 调整参数列表,不再需要req
    def procRequest(self):
        # 循环读取并处理收到的客户端请求
        while True:
            req = self.conn.recv()
            rsp = Response()
            rsp.id = req.id   
            if req.command == 'sayHello':
                rsp.result = self.sayHello()
            elif req.command == 'whoAreYou':
                rsp.result = self.whoAreYou()
            else:
                raise Exception("unknown command")
            
            # return rsp  # rsp也是通过connection最终传给client,而不是直接函数返回
            self.conn.send(rsp) 

最后,列一下connection的初始化
slist = []
    rlist = []
    client = Client(Connection(slist, rlist))
    server = Server(Connection(rlist, slist))
    server.start()


总结,引入传输层的意义在于
1. 实现client与server端的解耦,client端不再需要持有server端的对象了。 这也是实现“远程调用 ”所必须的。
2. 传输层的实现有很大的自由度,一般说来,他无需关心具体的RPC消息的格式,只需要完成数据的可靠传输就可以了。
3. 传输层具体基于socket,binder, 是采用http,udp,tcp这些都是自由的,根据需要选择就可以了。也就是相当于一个可以自由拼接的组件。
4. 上面的模型实在过于简单,没有考虑多线程保护,没有考虑异常。实际比较理想的情况,应该起码有个类,Connector,以及Channel。其中channel只负责数据的传输,Connector负责管理channel。
后续如果有时间,会再进行完善




### 关于RPC(远程过程调用) #### 定义与基本概念 远程过程调用是一种让客户端应用程序能够透明地调用服务器端子程序的技术,使得开发人员无需关注底层通信细节。通过这种方式,在不同计算机上的进程之间可以像在同一地址空间内一样相互协作[^3]。 #### 协议基础 为了使这种跨机器的过程调用成为可能,RPC依赖某些传输层协议来建立可靠的双向通讯链路。虽然最初的设计大多基于TCP/IP栈中的可靠流导向型服务——即面向连接的TCP协议;但也存在利用无连接的数据报UDP的情况,以及更复杂的场景下采用如VMTP这样的特殊目的协议来进行查询应答操作[^1]。 #### HTTP作为潜在载体 值得注意的是,随着Web的发展及其广泛应用,超文本传输协议(HTTP),作为一个运行在TCP之上的应用层协议,也被用来承载部分形式的RPC交互。尽管HTTP并非专门为RPC设计,但由于其简单性和普遍接受度,特别是在互联网环境中,它成为了RESTful风格API背后的事实标准之一[^2]。 #### 高性能计算环境下的挑战与发展 然而,在高性能计算(HPC)领域,传统的RPC框架面临着新的难题。由于这类系统往往配备有定制化的高速互连硬件,并且对于低延迟和高吞吐量有着严格的要求,因此传统基于套接字编程模型构建起来的标准库难以充分发挥潜力。为此,研究者们正在探索更加贴合实际需求的新一代解决方案,比如引入异步I/O模式和支持大容量数据集高效传递的能力,旨在克服现有局限性的同时保持良好的可移植性和灵活性。 ```python import xmlrpc.client def rpc_call(): proxy = xmlrpc.client.ServerProxy("http://localhost:8000/") result = proxy.add(7, 9) print(f"The sum is {result}") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值