2021SC@SDUSC-山大智云源码分析(11)

2021SC@SDUSC

searpc总结

经过之前的博客,我们分析完了searpc的源码,了解了其客户端与服务器端的工作原理。接下来从以下几个方面对其进行总结。

searpc是一个远程过程调用框架,其作用是使客户端能够通过网络从远程计算机程序上请求服务,而不需要了解底层的网络技术的思想。其具体过程如下:

在客户端方,程序通过向searpc-client传入函数名以及参数来调用远程函数,其中需要由开发者指定searpc-client传输函数(传输函数的作用是向远程服务器发送和调用函数有关的数据、并接受调用后的返回值);而在服务器端,在定义并向searpc-client注册好rpc函数之后,程序通过监听读出和调用rpc函数有关的数据,并传入到searpc-server,从而获取到函数调用结果,写回到客户端。

在以上过程中,客户端对函数名与参数的封装调用传输函数获取到结果对调用结果的解析以及服务器端存放rpc函数对接受到参数的解析找到对应的rpc函数对结果封装这些过程对使用者来说是透明的。

在上述过程中,服务器存放与寻找rpc函数时,是通过**signaturemarshal实现的。前者的作用是标识rpc函数;后者的作用是是实现解包、调用、封装过程。与它们的生成相关的过程在程序运行的最初**进行,并最终存生成特定的数据结构与函数,存放到对应的文件中。

同时我们也知道了,由于传输过程由用户定义的特性,我们得以基于不同方式对rpc过程进行实现,如socketnamed-pipe与异步调用等。

searpc也提供了基于python实现的包,用于在python环境下调用基于c的远程函数。其代码逻辑与基于c的searpc基本相同,故不再赘述。

基于python的searpc实现

在searpc的源码中,还提供了一个基于python的实现的包,可以通过import pysearpc直接使用

服务器端

class SearpcServer(object):
    def __init__(self):
        self.services = {}

    def create_service(self, svcname):
        service = SearpcService(svcname)
        self.services[svcname] = service

    def register_function(self, svcname, fn, fname=None):
        service = self.services[svcname]
        if fname == None:
            fname = fn.__name__
        service.func_table[fname] = fn

    def _call_function(self, svcname, fcallstr):
        """input str -> output str"""
        try:
            argv = json.loads(fcallstr)
        except Exception as e:
            raise SearpcError('bad call str: ' + str(e))

        service = self.services[svcname]

        fname = argv[0]
        fn = service.func_table.get(fname, None)
        if fn is None:
            raise SearpcError('No such funtion %s' % fname)

        ret = fn(*argv[1:])
        return ret

    def call_function(self, svcname, fcallstr):
        try:
            retVal = self._call_function(svcname, fcallstr)
        except Exception as e:
            ret = {'err_code': 555, 'err_msg': str(e)}
        else:
            ret = {'ret': retVal}

        return json.dumps(ret)

服务器端类

客户端

class SearpcClient(object):
    def call_remote_func_sync(self, fcall_str):
        raise NotImplementedError()

客户端类的父类,在pysearpc-demo-client.pynamed-pipe.py中均有对其的实现.
之所以对客户端定义基准父类,而服务器端使用可通用的类,是因为客户端的职能主要在于其传输函数,需要程序员对其进行实现;而父类的功能不需要程序员进行实现.

传输过程

class SearpcTransport(object):
    """
    A transport is repsonsible to send the serialized request to the
    server, and get back the raw response from the server.
    """
    def connect(self):
        raise NotImplementedError

    def send(self, service_name, request_str):
        raise NotImplementedError

这个类的作用是用于封装传输函数,无论是基于named-pipe还是socket的传输过程,都是通过继承这个类来实现的,以基于named-pipe的传输函数为例

class NamedPipeTransport(SearpcTransport):
    def __init__(self, socket_path):
        self.socket_path = socket_path
        self.pipe = None

    def connect(self):
        self.pipe = socket.socket(socket.AF_UNIX)
        self.pipe.connect(self.socket_path)

    def stop(self):
        if self.pipe:
            self.pipe.close()
            self.pipe = None

    def send(self, service, fcall_str):
        body = json.dumps({
            'service': service,
            'request': fcall_str,
        })
        body_utf8 = body.encode(encoding='utf-8')
        # "I" for unsiged int
        header = struct.pack('=I', len(body_utf8))
        sendall(self.pipe, header)
        sendall(self.pipe, body_utf8)

        resp_header = recvall(self.pipe, 4)
        # logger.info('resp_header is %s', resp_header)
        resp_size, = struct.unpack('=I', resp_header)
        # logger.info('resp_size is %s', resp_size)
        resp = recvall(self.pipe, resp_size)
        # logger.info('resp is %s', resp)
        return resp.decode(encoding='utf-8')

该传输函数类实现了连接,发送,停止三个操作
然后在此基础上的searpc-client

class NamedPipeClient(SearpcClient):
    def __init__(self, socket_path, service_name, pool_size=5):
        self.socket_path = socket_path
        self.service_name = service_name
        self.pool_size = pool_size
        self._pool = queue.Queue(pool_size)

    def _create_transport(self):
        transport = NamedPipeTransport(self.socket_path)
        transport.connect()
        return transport

    def _get_transport(self):
        try:
            transport = self._pool.get(False)
        except:
            transport = self._create_transport()
        return transport

    def _return_transport(self, transport):
        try:
            self._pool.put(transport, False)
        except queue.Full:
            transport.stop()

    def call_remote_func_sync(self, fcall_str):
        transport = self._get_transport()
        ret_str = transport.send(self.service_name, fcall_str)
        self._return_transport(transport)
        return ret_str

可以看到在这个类中基本上对客户端的所有操作进行了封装,相比于c语言实现可读性更强
其功能与原版的searpc完全一致,故不再赘述.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值