twisted:如何通过Perspective Broker发送和接收相同对象?
我有一个简单的“回声”PB客户端和服务器,客户端向服务器发送一个对象,服务器再把同样的对象发回客户端:
客户端:
from twisted.spread import pb
from twisted.internet import reactor
from twisted.python import util
from amodule import aClass
factory = pb.PBClientFactory()
reactor.connectTCP("localhost", 8282, factory)
d = factory.getRootObject()
d.addCallback(lambda object: object.callRemote("echo", aClass()))
d.addCallback(lambda response: 'server echoed: '+response)
d.addErrback(lambda reason: 'error: '+str(reason.value))
d.addCallback(util.println)
d.addCallback(lambda _: reactor.stop())
reactor.run()
服务器:
from twisted.application import internet, service
from twisted.internet import protocol
from twisted.spread import pb
from amodule import aClass
class RemoteClass(pb.RemoteCopy, aClass):
pass
pb.setUnjellyableForClass(aClass, RemoteClass)
class PBServer(pb.Root):
def remote_echo(self, a):
return a
application = service.Application("Test app")
# Prepare managers
clientManager = internet.TCPServer(8282, pb.PBServerFactory(PBServer()));
clientManager.setServiceParent(application)
if __name__ == '__main__':
print "Run with twistd"
import sys
sys.exit(1)
aClass是一个简单的类,它实现了可复制的功能:
来自twisted.spread的pb
class aClass(pb.Copyable):
pass
当我运行上面的代码时,出现了这个错误:
twisted.spread.jelly.InsecureJelly: 模块 builtin 不被允许(在类型 builtin.RemoteClass中)。
实际上,对象在发送到服务器时没有任何问题,因为它在服务器端通过pb.setUnjellyableForClass(aClass, RemoteClass)进行了安全处理,但一旦返回给客户端,就会出现这个错误。
我在寻找一种简单的方法来在两个对等方之间发送和接收我的对象。
1 个回答
Perspective broker(PB)在网络上交流时,通过名字来识别类。一个类的名字部分来源于它被定义的模块。一个比较棘手的问题是,当你在命令行运行一个文件(也就是你的“主脚本”)时,类的名字可能会让你感到意外。比如,当你这样做的时候:
python foo.py
Python给foo.py
中的代码的模块名并不是你想象中的"foo"
。实际上,它的名字是类似于"__main__"
的东西(这也是为什么if __name__ == "__main__":
这个技巧能用的原因)。
但是,如果你应用的其他部分后来尝试从foo.py
中导入某些东西,Python会重新评估它的内容,从而创建一个名为新模块"foo"
。
此外,一个进程中定义在"__main__"
模块里的类,可能和另一个进程中"__main__"
模块里的类没有任何关系。在你的例子中,__main__.RemoteClass
是在你的服务器进程中定义的,但在你的客户端进程的__main__
模块中并没有RemoteClass
。
所以,PB就会搞混,无法完成对象的传输。
解决这个问题的方法是尽量减少主脚本中的代码量,特别是不要在这里定义任何名字(不定义类,也不定义函数)。
不过,另一个问题是,大家可能会期待RemoteCopy
可以在PB中直接发送,而不需要额外的准备。其实,Copyable
可以被发送,从而在对端创建一个RemoteCopy
,但这并不是一个对称的关系。你的客户端也需要通过类似(或不同的)pb.setUnjellyableForClass
调用来允许这一点。