Twisted: Как отправить и получить один и тот же объект с помощью Perspective Broker? - PullRequest
0 голосов
/ 25 января 2012

У меня есть простой PB-клиент и сервер «echo», на котором клиент отправляет объект на сервер, который возвращает клиенту тот же объект:

Клиент:

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 - это простой класс, реализующий Copyable: из twisted.spread import pb

class aClass(pb.Copyable):
    pass

Когда я запускаю приведенный выше код, я получаю эту ошибку: twisted.spread.jelly.InsecureJelly: модуль встроенный недопустим (в типе встроенный .RemoteClass).

Фактически объект отправляется на сервер без каких-либо проблем.поскольку он был защищен с помощью pb.setUnjellyableForClass (aClass, RemoteClass) на стороне сервера, но как только он возвращается клиенту, возникает эта ошибка.

Ищу способ получения простого способа отправки/ получить мои объекты между двумя сверстниками.

1 Ответ

3 голосов
/ 25 января 2012

Перспективный брокер идентифицирует классы по имени, когда говорит о них по сети. Класс получает свое имя частично из модуля, в котором он определен. Сложная проблема с определением классов в файле, который вы запускаете из командной строки (т. Е. Ваш «основной сценарий»), заключается в том, что они могут в итоге получить неожиданное имя. Когда вы делаете это:

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.

...