Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何正确使用Pyro v.4.63中的第三方库_Python_Pyro_Pyro4 - Fatal编程技术网

Python 如何正确使用Pyro v.4.63中的第三方库

Python 如何正确使用Pyro v.4.63中的第三方库,python,pyro,pyro4,Python,Pyro,Pyro4,我对使用远程第三方库有点困惑: 1)例如, 我有服务器代码: import Pyro4 import Pyro4.naming import Pyro4.utils.flame Pyro4.config.REQUIRE_EXPOSE = False Pyro4.config.FLAME_ENABLED = True Pyro4.config.SERIALIZERS_ACCEPTED = set(["pickle"]) Pyro4.config.SERIALIZER = 'pickle' # f

我对使用远程第三方库有点困惑:

1)例如, 我有服务器代码:

import Pyro4
import Pyro4.naming
import Pyro4.utils.flame
Pyro4.config.REQUIRE_EXPOSE = False
Pyro4.config.FLAME_ENABLED = True
Pyro4.config.SERIALIZERS_ACCEPTED = set(["pickle"])
Pyro4.config.SERIALIZER = 'pickle'  # for flameserver


def _main():
    """Start RPC server."""
    ip_address = Pyro4.socketutil.getIpAddress(None, workaround127=True)
    ns_daemon = Pyro4.naming.NameServerDaemon(host=ip_address, port=RPC_PORT)
    Pyro4.utils.flame.start(ns_daemon)

    from remote_management.rpc.component.shell import Shell
    shell_uri = ns_daemon.register(Shell())
    ns_daemon.nameserver.register("shell", shell_uri)
    from remote_management.rpc.component.cpu import CPU
    cpu_uri = ns_daemon.register(CPU())
    ns_daemon.nameserver.register("cpu", cpu_uri)

    ns_daemon.requestLoop()
    ns_daemon.close()

if __name__ == "__main__":
    _main()
CPU组件如下所示:

import psutil

class CPU(object):
    def ps(self):
        return psutil.cpu_times()
import Pyro4
import Pyro4.utils.flame
import Pyro4.errors

Pyro4.config.SERIALIZER = "pickle"

proxy = Pyro4.Proxy("PYRONAME:cpu@myhost:47976")
print proxy.ps()
当我在客户端使用它时,如下所示:

import psutil

class CPU(object):
    def ps(self):
        return psutil.cpu_times()
import Pyro4
import Pyro4.utils.flame
import Pyro4.errors

Pyro4.config.SERIALIZER = "pickle"

proxy = Pyro4.Proxy("PYRONAME:cpu@myhost:47976")
print proxy.ps()
我得到一个错误:

Traceback (most recent call last):
  File "t.py", line 145, in <module>
    print proxy.ps()
  File "/home/korolev/.envs/auto/lib/python2.7/site-packages/Pyro4/core.py", line 187, in __call__
    return self.__send(self.__name, args, kwargs)
  File "/home/korolev/.envs/auto/lib/python2.7/site-packages/Pyro4/core.py", line 464, in _pyroInvoke
    data = serializer.deserializeData(msg.data, compressed=msg.flags & message.FLAGS_COMPRESSED)
  File "/home/korolev/.envs/auto/lib/python2.7/site-packages/Pyro4/util.py", line 170, in deserializeData
    return self.loads(data)
  File "/home/korolev/.envs/auto/lib/python2.7/site-packages/Pyro4/util.py", line 451, in loads
        return pickle.loads(data)

ImportError: No module named psutil._pslinux
如果我需要远程模块,但本地没有,为什么我不能这样做:

import psutil

class CPU(object):
    def ps(self):
        return psutil.cpu_times()
import Pyro4
import Pyro4.utils.flame
import Pyro4.errors

Pyro4.config.SERIALIZER = "pickle"

proxy = Pyro4.Proxy("PYRONAME:cpu@myhost:47976")
print proxy.ps()
注册器组件:

class ModuleRegistrator(object):
    def register(self, module):
        module = importlib.import_module(module)
        self._pyroDaemon.register(module)
        return module
因此,当我在客户端使用它时:

proxy = Pyro4.Proxy("PYRONAME:module_registrator@myhost:47976")
print proxy.register("psutil").cpu_times()
我得到一个错误:

Traceback (most recent call last):
  File "t.py", line 145, in <module>
    print proxy.register('psutil').cpu_times()
  File "/home/korolev/.envs/auto/lib/python2.7/site-packages/Pyro4/core.py", line 279, in __getattr__
    raise AttributeError("remote object '%s' has no exposed attribute or method '%s'" % (self._pyroUri, name))
AttributeError: remote object 'PYRONAME:module_registrator@myhost:47976' has no exposed attribute or method 'register'
回溯(最近一次呼叫最后一次):
文件“t.py”,第145行,在
打印代理。寄存器('psutil')。cpu\U时间()
文件“/home/korolev/.envs/auto/lib/python2.7/site packages/Pyro4/core.py”,第279行,在__
raise AttributeError(“远程对象'%s'没有公开的属性或方法'%s'”(self.\u pyroUri,name))
AttributeError:远程对象的PYRONAME:模块_registrator@myhost:47976'没有公开的属性或方法'register'

请帮助我理解这些错误以及我遗漏了什么?在与第三方远程协作时,处理此类问题的最佳方法是什么?提前谢谢

首先,您似乎正在使用Pyro4的“flame”功能,这需要
pickle
序列化协议。这是强大的,但并非没有问题。 您确定要/需要使用flame吗?我希望你知道它的安全影响

现在,你的实际问题由三部分组成(试着让你未来的问题更多地只涉及一个问题,这样回答起来就简单多了)

回答问题的第一部分: 正如您自己已经发现的那样,您不能假设所有类型都可以通过网络传输,并神奇地在另一端工作。特别是对于
pickle
而言,这仅在 类型已定义,在两侧都可用。 在您的情况下,
psutil
模块似乎在客户端不可用,因此当它尝试反序列化由
psutil.cpu\u times()返回的对象时出现pickle错误

解决方案可以是在客户端安装
psutil
。 您还发现了另一种解决方案:不要通过导线传递自定义类型的对象,而是尽可能多地使用内置类型。将结果转换为元组、列表或dict时, 这些对象可以被序列化和反序列化,而不会出现任何问题(如果它们包含的所有对象也是内置类型的)

回答问题的第二部分: 这段代码看起来像是在试图找到解决第一个问题的方法? 无论如何,错误应该是清楚的;它的意思是:代理所连接的远程对象没有公开您试图调用的方法。你应该添加一个
@Pyro4.expose
装饰 以正确地暴露它

也就是说,您已经在使用Flame,那么为什么不使用它的远程模块功能呢?看

例如(我假设您在客户端安装了
psutil
):

最后 要回答您的问题“在远程与第三方合作时,处理此类问题的最佳方法是什么”:

  • 尽量不要公开正在使用的API的详细信息和类型,尽量将其减少为内置类型。 如果操作正确,还可以简单地使用Pyro的默认序列化程序(serpent)而不是pickle,并且不存在任何安全问题。(这确实需要一种不依赖于火焰的解决方案,见下一个项目)
  • 不要使用Flame,除非您完全确定您对它的安全影响没有意见,并且无法以其他方式解决问题。相反,创建一个普通的Pyro服务器类,并使用您自己编写的专用自定义API
  • 只公开实际需要远程访问的远程方法

稍后我将尝试回答这个问题,但首先让我问一下:您对
pickle
及其限制有多熟悉?谢谢。我知道pickle非常肤浅,我只抓住了一般概念——它用于(反)序列化python对象。我所知道的限制几乎是一样的——在我读过的某个地方,PyTime对象不能被pickle,定义的类的范围也很重要(可以导入)。但我会挖掘更多的信息首先,谢谢你-现在整个画面对我来说更清楚。关于使用“flame”功能-是的,我知道它的安全含义。这对我来说没关系,因为我在自动测试中使用它。至于问题的第二部分-我已经设置了
Pyro4.config.REQUIRE\u EXPOSE=False
,所以我认为没有必要明显地添加
Pyro4.EXPOSE
。无论如何,我将进一步介绍另一种方法——远程计算机上的prepare方法,它将转换为内置类型,因为我无法在构建代理上安装第三方。奇怪的是,这让你看到了错误。我可能会更深入地了解这一点,看看是怎么回事。我已经尝试运行了您提供的源代码,但我无法重现您报告的错误。我得到了其他错误,这些错误已经解释过了,因为您试图返回一个模块,正如我已经解释过的,这不起作用。如果您仍然遇到问题,请提出一个新问题,说明实际的源代码和您遇到的确切错误。最后一个提示:如果您使用的是PYRONAME uri方案,通常不必在uri中提供主机名和端口