我对使用远程第三方库感到困惑:
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()
我收到错误:
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
如您所见,无法反序列化。如果我改变回到:
return tuple(psutil.cpu_times())
,然后就可以了。
2)我认为下一个问题具有相同的性质: 除组件
外,服务器代码几乎相同from remote_management.rpc.component.registrator import ModuleRegistrator
reg_uri = ns_daemon.register(ModuleRegistrator())
ns_daemon.nameserver.register("module_registrator", reg_uri)
如果我需要远程模块,但在本地没有它,为什么我不能这样做:
Registrator组件:
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'
请帮助我理解这些错误以及我遗失的地方?在与第三方远程协作时,处理这类事情的最佳方法是什么?提前谢谢!
答案 0 :(得分:2)
首先,您似乎正在使用&#39;火焰&#39; Pyro4的功能,需要pickle
序列化协议。这很强大,但并非没有问题。
你确定你想要/需要使用火焰吗?我希望你知道它的安全隐患。 http://pyro4.readthedocs.io/en/latest/flame.html
现在,您的实际问题包含三个部分(尝试让您的未来问题更多地仅针对一个问题,这使得回答它们变得更加简单)
正如您已经发现的那样,您不能假设所有类型都可以通过网络传输,并且神奇地只是在另一侧工作。特别是对于pickle
,这仅适用于其中的模块
类型是定义的,双方都可以使用。
在您的情况下,似乎psutil
模块在您的客户端不可用,因此当它尝试反序列化psutil.cpu_times()
返回的对象时出现pickle错误。
解决方案可能是在您的客户端安装psutil
。
您还发现了另一种解决方案:不要通过线路传递自定义类型的对象,但尽可能坚持内置类型。将结果转换为元组或列表或字典时,
这些可以序列化和反序列化而不会出现任何问题(如果它们包含的所有对象都是内置类型的话)。
此代码看起来像您在第一个问题中尝试找到问题的解决方法?
无论如何,错误应该是明确的;它意味着它所说的:您的代理连接到的远程对象,并没有暴露您尝试呼叫的方法。您应该添加@Pyro4.expose
装饰
正确揭露它。
那就是说,你已经使用了Flame,那你为什么不使用它的远程模块功能呢?见http://pyro4.readthedocs.io/en/latest/flame.html#flame-object-and-examples
例如(我假设您在客户端安装了psutil
):
import Pyro4.utils.flame
Pyro4.config.SERIALIZER = "pickle"
flame = Pyro4.utils.flame.connect("yourhost:9999")
psutilmodule = flame.module("psutil")
print("remote cpu:", psutilmodule.cpu_times())
解决您的问题&#34;在远程使用第三方时处理此类事情的最佳方法是什么?