Pergunta

Eu tenho um cliente e servidor PB 'echo' simples, onde o cliente envia um objeto para o servidor que ecoa o mesmo objeto de volta para o cliente:

O cliente:

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()

O servidor:

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)

A aClass é uma classe simples que implementa Copyable:de twisted.spread importar pb

class aClass(pb.Copyable):
    pass

Quando executo o código acima, recebo este erro:torcido.spread.jelly.InsecureJelly:Módulo construídas em não permitido (no tipo construídas em.RemoteClass).

Na verdade, o objeto é enviado ao servidor sem nenhum problema, pois foi protegido com pb.setUnjellyableForClass(aClass, RemoteClass) no lado do servidor, mas assim que for retornado ao cliente, esse erro será gerado.

Estou procurando uma maneira fácil de enviar/receber meus objetos entre dois pares.

Foi útil?

Solução

O corretor de perspectiva identifica as classes pelo nome ao falar sobre elas na rede.Uma classe recebe seu nome em parte do módulo no qual está definida.Um problema complicado com a definição de classes em um arquivo executado a partir da linha de comando (ou seja, seu "script principal") é que elas podem acabar com um nome surpreendente.Quando você faz isso:

python foo.py

O nome do módulo que o Python dá ao código em foo.py não é "foo" como seria de esperar.Em vez disso, é algo como "__main__" (é por isso que if __name__ == "__main__": truque funciona).

No entanto, se alguma outra parte do seu aplicativo tentar importar algo posteriormente foo.py, então Python reavalia seu conteúdo para criar um novo módulo nomeado "foo".

Além disso, as classes definidas no "__main__" módulo de um processo pode não ter nada a ver com as classes definidas no "__main__" módulo de outro processo.Este é o caso do seu exemplo, onde __main__.RemoteClass está definido no processo do seu servidor, mas não há RemoteClass no __main__ módulo do seu processo de cliente.

Então, o PB se confunde e não consegue concluir a transferência do objeto.

A solução é manter ao mínimo a quantidade de código em seu script principal e, em particular, nunca definir coisas com nomes (sem classes, sem definições de funções).

Contudo, outro problema é a expectativa de que um RemoteCopy pode ser enviado por PB sem preparação adicional.A Copyable pode ser enviado, criando um RemoteCopy no par, mas esta não é uma relação simétrica.Seu cliente também precisa permitir isso fazendo uma abordagem semelhante (ou diferente) pb.setUnjellyableForClass chamar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top