龙空技术网

Python远程过程调用

青少年编程ABC 486

前言:

此刻大家对“python模块调用的用法”大体比较着重,看官们都需要了解一些“python模块调用的用法”的相关知识。那么小编也在网摘上网罗了一些有关“python模块调用的用法””的相关内容,希望姐妹们能喜欢,各位老铁们一起来了解一下吧!

Python远程过程调用1.RPyc

RPyC(远程Python调用)是一个透明的Python库,用于对称的远程过程调用、集群和分布式计算。RPyC利用对象代理(object proxying,一种利用python动态特性的技术)来克服进程和计算机之间的物理界限,从而可以像本地对象一样操作远程对象。

2.安装

pip install rpyc
3.RPyC编程模型

从RPyC 3.00开始,RPyC编程模型是基于服务的。服务提供了一种向另一方公开定义良好的功能集的方法,这使RPyC成为一个通用的RPC平台。示例如下:

import rpycclass MyService(rpyc.Service):    def on_connect(self, conn):        # code that runs when a connection is created        # (to init the service, if needed)        pass    def on_disconnect(self, conn):        # code that runs after the connection has already closed        # (to finalize the service, if needed)        pass    def exposed_get_answer(self): # this is an exposed method        return 42    exposed_the_real_answer_though = 43     # an exposed attribute    def get_question(self):  # while this method is not exposed        return "what is the airspeed velocity of an unladen swallow?"

rpyc 4.0中添加了on_connect和on_disconnect的conn参数。

在上面的代码中,正如您所见,除了特殊的初始化 / 终结方法之外,您可以像其他任何类一样自由定义该类。但是,与常规类不同,您可以选择将哪些属性公开给另一方:如果名称以exposed_开头,则该属性将可以远程访问,否则只能在本地访问。在本例中,客户端可以调用get_-answer,但不能调用 get_question,稍后我们将看到这一点。

然而,要向世界公开您的服务,您需要启动一台服务器。有很多方法可以做到这一点,但最简单的是:

# ... continuing the code snippet from above ...if __name__ == "__main__":    from rpyc.utils.server import ThreadedServer    t = ThreadedServer(MyService, port=18861)    t.start()

对于远程方,服务作为连接的根对象公开,例如conn.root。远程方调用示例如下:

>>> import rpyc>>> c = rpyc.connect("localhost", 18861)>>> c.root<__main__.MyService object at 0x834e1ac>

“根对象”是对服务器进程中的服务实例的引用。它可以用于访问和调用公开的属性和方法:

>>> c.root.get_answer()42>>> c.root.the_real_answer_though43

对于未公开的属性和方法:

>>> c.root.get_question()======= Remote traceback =======...  File "/home/tomer/workspace/rpyc/core/protocol.py", line 298, in sync_request    raise objAttributeError: cannot access 'get_question'
3.1访问策略

默认情况下,只有当方法和属性以exposed_前缀开头时,它们才可见。这也意味着默认情况下无法访问列表或dict等内置对象的属性。如果需要,您可以通过在创建服务器时传递适当的选项来进行配置。例如:

from rpyc.utils.server import ThreadedServerserver = ThreadedServer(MyService, port=18861, protocol_config={    'allow_public_attrs': True,})server.start()

有关所有可用设置的说明,请参阅默认配置:

参数

Default value

Description

allow_safe_attrs

True

是否允许使用safe属性

allow_exposed_attrs

True

是否允许公开属性(以'exposed_前缀'开头的属性)

allow_public_attrs

False

是否允许公共属性(不以“_”开头的属性)

allow_all_attrs

False

是否允许所有属性(包括私有)

safe_attrs

set([...])

被认为是安全的属性集

exposed_prefix

"exposed_"

暴露属性的前缀

allow_getattr

True

是否允许获取属性(getattr

allow_setattr

False

是否允许设置属性(setattr

allow_delattr

False

是否允许删除属性(delattr

allow_pickle

False

是否允许使用“pickle”

include_local_traceback

True

是否在远程异常中包含本地回溯

instantiate_custom_exceptions

False

是否允许实例化自定义异常(不是内置异常)

import_custom_exceptions

False

是否允许从尚未导入的模块导入异常

instantiate_oldstyle_exceptions

False

是否允许实例化不是从“Exception”派生的异常。这不适用于Python 3及更高版本。

propagate_SystemExit_locally

False

是在本地传播“SystemExit”(终止服务器)还是向另一方传播(终止客户端)

propagate_KeyboardInterrupt_locally

False

是在本地传播“KeyboardInterrupt”(终止服务器)还是向另一方传播(终止客户端)

logger

None

用于记录异常(在发送给另一方之前)和其他事件的日志实例。如果“无”,则不会进行日志记录。

connid

None

运行时:RPyC连接ID(主要用于调试目的)

credentials

None

运行时: 服务器的[authenticator]返回的credentails对象

endpoints

None

运行时: 连接的端点。这是一个由本地套接字端点(getsockname)和远程套接字端点(getpeername)组成的元组。这由服务器在接受连接时设置;客户端连接没有设置此配置选项。

sync_request_timeout

30

等待结果的默认超时

3.2共享服务实例

请注意,我们在这里将类MyService传递给服务器,其效果是每个传入连接都将使用自己的独立MyService实例作为根对象。如果您传入一个实例,所有传入的连接都将使用该实例作为其共享根对象,例如:

t = ThreadedServer(MyService(), port=18861)

从rpyc 4.0开始,支持传递实例。在早期版本中,您只能传递一个类,其中每个连接将接收一个单独的实例。

3.3向服务传递参数

在第二种情况下,传入一个完全构造的服务实例,向_init__函数传递额外的参数是很简单的。但是,如果要在分离每个连接的根对象的同时传递参数,则情况会稍微复杂一些。在本例中,使用classpartial()如下:

from rpyc.utils.helpers import classpartialservice = classpartial(MyService, 1, 2, pi=3)t = ThreadedServer(service, port=18861)

classpartial是在4.0版中添加的。

3.4服务名称

所有服务都有一个名称,通常是类的名称,减去“服务”后缀。在我们的例子中,服务名称是“MY”(服务名称不区分大小写)。如果要定义自定义名称或多个名称(别名),可以通过设置别名列表来定义。第一个别名被认为是“正式名称”,而其他别名是:

class MyService(rpyc.Service):    ALIASES = ["floop", "bloop"]    ...

在原始代码片段中,客户机得到的是:

>>> c.root.get_service_name()'MY'>>> c.root.get_service_aliases()('MY',)

服务具有名称的原因是服务注册表:通常情况下,服务器会将其详细信息广播到附近的注册表服务器以供发现。要使用服务发现,请确保启动 bin/rpyc_registry.py 。该服务器监听广播UDP套接字,并将回答有关哪些服务在何处运行的查询。

一旦注册服务器在网络上的某个“可广播”位置运行,并且服务器配置为自动注册(默认设置),客户端就可以自动发现服务。要启动服务器,请执行以下操作:

>>> mysvc = rpyc.OneShotServer(service=MyService, port=18861, auto_register=True)>>> mysvc.start()

要查找运行给定服务名称的服务器,请执行以下操作:

>>> rpyc.list_services()>>> rpyc.discover("MY")(('192.168.1.101', 18861),)

如果您不关心连接到哪个服务器,请使用connect_by_service:

>>> c2 = rpyc.connect_by_service("MY")>>> c2.root.get_answer()42
3.5解耦服务

到目前为止,我们只讨论了服务器公开的服务,但是客户端呢?客户端是否也公开了服务?毕竟,RPyC是一个对称协议——客户端和服务器之间没有区别。正如您可能已经猜到的,答案是肯定的:客户端和服务器都公开服务。然而,双方公开的服务不一定是相同的——它们是解耦的。

默认情况下,客户端(使用connect()函数连接到服务器)公开VoidService。顾名思义,该服务不向另一方公开任何功能,这意味着服务器不能向客户端发出请求(除了显式传递的功能,如函数回调)。通过将service=参数传递给connect()函数,可以设置客户端公开的服务。

连接两端的服务是解耦的,这并不意味着它们可以是任意的。例如,“服务A”可能会连接到“服务B”——如果不是这样,就会出现运行时错误(主要是AttributeError)。很多时候,两端的服务可能不同,但请记住,如果需要双方之间的交互,两个服务必须“兼容”。

标签: #python模块调用的用法