Outils pour utilisateurs

Outils du site


using_perspective_broker

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
using_perspective_broker [2022/11/28 17:48] – [Using Perspective Broker] sergeusing_perspective_broker [2022/12/16 10:42] (Version actuelle) – [Using Perspective Broker] serge
Ligne 1: Ligne 1:
 ======Using Perspective Broker====== ======Using Perspective Broker======
 +{{ :media_01:apkv_20.svg |}}
 +
 +{{ ::labo.svg |}}
 +
 <WRAP center round info centeralign 60%> <WRAP center round info centeralign 60%>
-**Niveau Pro et intergalactique !**+**Niveau Pro et intergalactique !**\\ 
 +Cette API: 
 +  * a entre 15 et 20 ans 
 +  * n'est que vaguement maintenu 
 +  * un exemple au moins ne marche pas 
 +  * le tranfert de datas simples marche 
 +  * le transfert d'objets complexes ne marche pas 
 +  * les exemples ne respectent pas le PEP 8, c'est imbriqué au possible
 </WRAP> </WRAP>
  
-<WRAP center round box 60% centeralign>+<WRAP center round box 60% >
   * **{{tagpage>perspectivebroker|Toutes les pages Twisted Perspective Broker}}**   * **{{tagpage>perspectivebroker|Toutes les pages Twisted Perspective Broker}}**
-  * **[[perspective_broker|Page précédente]]**+  * **[[perspective_broker|Page précédente]]** Python: Twisted Perspective Broker 
 +  * **[[managing_clients_of_perspectives|Page suivante]]** Managing Clients of Perspectives 
 +  * **[[https://github.com/sergeLabo/PB|Les fichiers sources]]**
 </WRAP> </WRAP>
  
Ligne 12: Ligne 25:
 https://docs.twistedmatrix.com/en/stable/core/howto/pb-usage.html|Using Perspective Broker]] améliorée par un humain ayant fait intergalactique en 1ère langue !** https://docs.twistedmatrix.com/en/stable/core/howto/pb-usage.html|Using Perspective Broker]] améliorée par un humain ayant fait intergalactique en 1ère langue !**
  
 +=====Exemple simple=====
 +**Passez votre chemin**, cela revient à expliquer la factorisation à un élève de 5ème, en lui parlant de nombres complexes et de cosinus hyperbolique: pourquoi utiliser des "lambda" qui ne sont pas pythoniques ???? m( et en plus gérer les erreurs !\\
 +Tout simplement pour avoir un exemple court, malheureusement comme c'est court, on y comprends rien, pour un Hello World, c'est raté.\\
 +Pas grave, nous allons comprendre la suite ! 8-)
  
  
-=====Des exemples===== +=====Exemple 1===== 
-Bon là, je ne comprends pas, c'est de l'intergalactique! +  * **[[https://docs.twistedmatrix.com/en/stable/core/howto/pb-usage.html#complete-example|docs.twistedmatrix.com Complete Example]]**
- +
-====Exemple 1==== +
-<file python pb1client.py> +
-#!/usr/bin/env python3 +
- +
-# Copyright (c) Twisted Matrix Laboratories. +
-# See LICENSE for details.+
  
 +La méthode **remote_three()** du serveur est appelée par le client avec
 +  obj2.callRemote("three", 12)
 +De manière générale, sur le client, on peut appeler **remote_toto(un_argument)** avec
 +  truc.callRemote("toto", un_argument)
 +Cela appelle la méthode à distance et cela transfert un_argument du client au serveur!\\
 +La taille maxi de l'argument est décrit [[https://docs.twistedmatrix.com/en/stable/core/howto/pb-limits.html|ici]]: 640 * 1024 bytes ou entier de +ou- 2<sup>448</sup>\\
 +Cette façon de procéder est une des 3 façons possibles(saveurs).
  
 +<file python pb1server.py>
 from twisted.spread import pb from twisted.spread import pb
 +class Two(pb.Referenceable):
 +    def remote_three(self, arg):
 +        """Appelé par le callback three sur le client
 +        obj2.callRemote("three", 12)
 +        """
 +        print("Two.three was given", arg)
 +class One(pb.Root):
 +    def remote_getTwo(self):
 +        """Appelé par le callback getTwo sur le client
 +        def2 = obj1.callRemote("getTwo")
 +        """
 +        two = Two()
 +        print("returning a Two called", two)
 +        return two
 from twisted.internet import reactor from twisted.internet import reactor
 +reactor.listenTCP(8800, pb.PBServerFactory(One()))
 +reactor.run()
 +</file>
  
 +<file python pb1client.py>
 +from twisted.spread import pb
 +from twisted.internet import reactor
 def main(): def main():
     factory = pb.PBClientFactory()     factory = pb.PBClientFactory()
     reactor.connectTCP("localhost", 8800, factory)     reactor.connectTCP("localhost", 8800, factory)
     def1 = factory.getRootObject()     def1 = factory.getRootObject()
-    def1.addCallbacks(got_obj1, err_obj1)+    def1.addCallbacks(got_obj1)
     reactor.run()     reactor.run()
- 
-def err_obj1(reason): 
-    print("error getting first object", reason) 
-    reactor.stop() 
- 
 def got_obj1(obj1): def got_obj1(obj1):
     print("got first object:", obj1)     print("got first object:", obj1)
Ligne 44: Ligne 77:
     def2 = obj1.callRemote("getTwo")     def2 = obj1.callRemote("getTwo")
     def2.addCallbacks(got_obj2)     def2.addCallbacks(got_obj2)
- 
 def got_obj2(obj2): def got_obj2(obj2):
     print("got second object:", obj2)     print("got second object:", obj2)
     print("telling it to do three(12)")     print("telling it to do three(12)")
     obj2.callRemote("three", 12)     obj2.callRemote("three", 12)
 +main()
 +</file>
 +====Explications====
 +
 +=====Exemple 2: Accès aux objets du serveur depuis le client=====
 +  * **[[https://docs.twistedmatrix.com/en/stable/core/howto/pb-usage.html#references-can-come-back-to-you|docs.twistedmatrix.com References can come back to you]]**
 +
 +Si votre serveur donne une référence(à un objet) à un client, puis que ce client renvoie la référence au serveur, le serveur se retrouvera avec le même objet qu'il a donné à l'origine. La couche de sérialisation surveille le retour des identifiants de référence et les transforme en objets réels. Vous devez rester conscient de l'emplacement de l'objet : s'il est de votre côté, vous effectuez des appels de méthode réels. Si c'est de l'autre côté, vous faites des .callRemote()(appel à distance).\\
 +Cela crée 2 univers identiques. Les objets sont les mêmes mais pas au mêmes endroits: un sur le serveur, un sur le client.
 +
 +En renommant astucieusement les variables, c'est beaucoup plus clair !!
 +====Code====
 +<file python pb2server.py>
 +"""
 +Accès aux objets de ce serveur depuis le client.
 +Cet exemple montre que c'est bien les mêmes, mais les univers parallèles créent
 +un peu de trouble.
 +
 +Le client vient accéder ici client_accessible = ObjetAccessibleParLeClient()
 +
 +Le client appelle
 +    - remote_getTwo avec self.oneRef.callRemote("getTwo").addCallback(self.step2)
 +    - remote_checkTwo avec self.oneRef.callRemote("checkTwo", two)
 +
 +"""
 +
 +from twisted.internet import reactor
 +from twisted.spread import pb
 +
 +class ObjetAccessibleParLeClient(pb.Referenceable):
 +    """Cette class permet de créer un objet pour en avoir un à partager,
 +    mais il ne fait rien dans cet exemple
 +    L'objet accessible par le client est client_accessible
 +    """
 +    pass
 +
 +class ObjetPrincipal(pb.Root):
 +    def __init__(self, client_accessible):
 +        self.client_accessible = client_accessible
 +
 +    def remote_getObject(self):  # ancien remote_getTwo
 +        """Méthode appelée par "getTwo" chez le client avec
 +        self.oneRef.callRemote("getTwo").addCallback(self.step2)
 +        """
 +        print(f"One.getTwo(), returning my client_accessible called", self.client_accessible)
 +        return self.client_accessible
 +
 +    def remote_checkObject(self, new_client_accessible):  # ancien remote_checkTwo
 +        """Méthode appelée par "checkTwo" chez le client
 +        self.oneRef.callRemote("checkTwo", client_accessible)
 +        """
 +        print(f"My client_accessible is: {self.client_accessible}")
 +        print(f"Le client_accessible is: {new_client_accessible}")
 +        if self.client_accessible == new_client_accessible:
 +            print("client_accessible are the same")
 +
 +# un object auquel le client pourra accéder
 +client_accessible = ObjetAccessibleParLeClient()
 +
 +# L'objet principal réseau qui tourne
 +root_obj = ObjetPrincipal(client_accessible)
 +
 +reactor.listenTCP(8800, pb.PBServerFactory(root_obj))
 +reactor.run()
 +</file>
 +
 +<file python pb2client.py>
 +"""
 +Accès aux objets du serveur depuis le client
 +Cet exemple montre que c'est bien les mêmes, mais les univers parallèles créent
 +un peu de trouble.
 +
 +Ce client accède à:
 +    - remote_getObject avec callRemote sur "getObject"
 +    - remote_checkObject avec callRemote sur "checkObject"
 +du serveur.
 +"""
 +from twisted.internet import reactor
 +from twisted.spread import pb
 +
 +
 +def main():
 +    foo = Foo()
 +    factory = pb.PBClientFactory()
 +    reactor.connectTCP("localhost", 8800, factory)
 +    factory.getRootObject().addCallback(foo.step1)
 +    reactor.run()
 +
 +class Foo:
 +    """Permet de créer l'objet principal client qui tourne"""
 +    def __init__(self):
 +        """self.root_obj_client sera l'objet principal du serveur root_obj"""
 +        self.root_obj_client = None
 +
 +    def step1(self, obj):
 +        print(f"step1: got client_accessible object from server = {obj}")
 +        self.root_obj_client = obj
 +        print("Appel de getObject sur le serveur et ajout du callback")
 +        self.root_obj_client.callRemote("getObject").addCallback(self.step2)
 +
 +    def step2(self, client_accessible):
 +        print(f"Got object from server: {client_accessible}")
 +        print(f"Giving it back to server: {self.root_obj_client}")
 +        self.root_obj_client.callRemote("checkObject", client_accessible)
  
 main() main()
 </file> </file>
-<file python pb1server.py> 
-#!/usr/bin/env python3 
  
-# Copyright (c) Twisted Matrix Laboratories. +====Explications==== 
-# See LICENSE for details.+Le serveur donne une Two()instance au client, qui renvoie ensuite la référence au serveur. Le serveur compare les "deux" donnés avec les "deux" reçus et montre qu'ils sont identiques, et que les deux sont des objets réels au lieu de références distantes.\\ 
 +Quelques autres techniques sont démontrées dans pb2client.py. La première est que les rappels sont ajoutés avec .addCallback au lieu de .addCallbacks. Comme vous pouvez le voir dans la documentation Deferred.addCallback , il s'agit d'un formulaire simplifié qui n'ajoute qu'un rappel de réussite. L'autre est que pour garder une trace de l'état d'un rappel à l'autre (la référence distante à l'objet principal One()), nous créons une classe simple, stockons la référence dans une instance de celle-ci et pointons les rappels vers une séquence de méthodes liées. C'est un moyen pratique d'encapsuler une machine d'état. Chaque réponse lance la méthode suivante, et toutes les données qui doivent être transportées d'un état à l'autre peuvent simplement être enregistrées en tant qu'attribut de l'objet.\\ 
 +N'oubliez pas que le client peut vous rendre toute référence à distance que vous lui avez donnée. Ne basez pas votre serveur de **transactions boursières de plusieurs milliards de dollars** sur l'idée que **vous faites confiance au client** pour vous donner la bonne référence. Le modèle de sécurité inhérent à PB signifie qu'ils ne peuvent vous rendre qu'une référence que vous leur avez donnée pour la connexion en cours (pas celle que vous avez donnée à quelqu'un d'autre à la place, ni celle que vous leur avez donnée la dernière fois avant la fin de la session TCP, ni celui que vous n'avez pas encore donné au client), mais tout comme avec les URL et les cookies HTTP, la référence particulière qu'ils vous donnent est entièrement sous leur contrôle. 
 +=====Exemple 3: Accès aux objets coté client===== 
 +  * **[[https://docs.twistedmatrix.com/en/stable/core/howto/pb-usage.html#references-to-client-side-objects|docs.twistedmatrix.com Références aux objets côté client]]**
  
 +Tout ce qui est référençable peut être transmis sur le fil, dans les deux sens . Le "client" peut donner une référence au "serveur", puis le serveur peut utiliser .callRemote() pour invoquer des méthodes côté client. Cela brouille la distinction entre « client » et « serveur » : la seule vraie différence est qui initie la connexion TCP d'origine ; après c'est tout symétrique.
 +====Code====
 +One est l'objet principal du serveur\\
 +Two est l'objet du client
 +<file python pb3server.py>
 +from twisted.internet import reactor
 from twisted.spread import pb from twisted.spread import pb
 +class One(pb.Root):
 +    def remote_takeTwo(self, two):
 +        """takeTwo"""
 +        print("received a Two called", two)
 +        print("telling it to print(12)")
 +        two.callRemote("print", 12)
 +reactor.listenTCP(8800, pb.PBServerFactory(One()))
 +reactor.run()
 +</file>
  
 +<file python pb3client.py>
 +from twisted.internet import reactor
 +from twisted.spread import pb
 class Two(pb.Referenceable): class Two(pb.Referenceable):
-    def remote_three(self, arg): +    def remote_print(self, arg): 
-        print("Two.three was given", arg) +        print("Two.print() called with", arg) 
-         +def main(): 
-class One(pb.Root): +    two = Two() 
-    def remote_getTwo(self): +    factory = pb.PBClientFactory() 
-        two = Two() +    reactor.connectTCP("localhost", 8800, factory) 
-        print("returning a Two called", two) +    def1 = factory.getRootObject() 
-        return two+    def1.addCallback(got_obj, two)  # hands our 'two' to the callback 
 +    reactor.run() 
 +def got_obj(obj, two): 
 +    print("got One:", obj) 
 +    print("giving it our two") 
 +    obj.callRemote("takeTwo", two) 
 +main() 
 +</file> 
 +====Explications==== 
 +Dans cet exemple, le client donne une référence à son propre objet au serveur. Le serveur appelle ensuite une méthode distante sur l'objet côté client.
  
 +=====Exemple 4: Echanges bidirectionnels=====
 +Cet exemple est trop confus, il est le mélange de 2 et 3. Il est une étape intermédiaire avec l'exemple 5.
 +====Code====
 +<file python pb4server.py>
 +"""
 +Serveur: Echange bidirectionnel serveur client
 +"""
 from twisted.internet import reactor from twisted.internet import reactor
-reactor.listenTCP(8800, pb.PBServerFactory(One()))+from twisted.spread import pb 
 + 
 +class ObjetAccessibleParLeClient(pb.Referenceable): 
 +    """Cette class permet de créer un objet pour en avoir un à partager, 
 +    mais il ne fait rien dans cet exemple 
 +    L'objet accessible par le client est client_accessible 
 +    """ 
 +    pass 
 + 
 +class ObjetPrincipal(pb.Root): 
 +    def __init__(self, client_accessible): 
 +        self.client_accessible = client_accessible 
 +    def remote_getObject(self):  # ancien remote_getTwo 
 +        """Méthode appelée par "getObject" chez le client avec 
 +            self.oneRef.callRemote("getObject").addCallback(self.step2) 
 +        """ 
 +        print(f"Le client a reçu: {self.client_accessible}") 
 +        return self.client_accessible 
 +    def remote_checkObject(self, new_client_accessible):  # ancien remote_checkTwo 
 +        """Méthode appelée par "checkTwo" chez le client 
 +        self.oneRef.callRemote("checkTwo", client_accessible) 
 +        """ 
 +        print(f"Mon client_accessible est: {self.client_accessible}") 
 +        print(f"Le client_accessible est:  {new_client_accessible}") 
 +        if self.client_accessible == new_client_accessible: 
 +            print("Les client_accessible sont les mêmes") 
 +    def remote_takeTwo(self, two): 
 +        """takeTwo""" 
 +        print(f"Le serveur à reçu du client un Two: {two}") 
 +        print("Le serveur demande au client: print(12)") 
 +        two.callRemote("print", 12) 
 + 
 +# un object auquel le client pourra accéder 
 +client_accessible = ObjetAccessibleParLeClient() 
 +# L'objet principal réseau qui tourne 
 +root_obj = ObjetPrincipal(client_accessible) 
 +reactor.listenTCP(8800, pb.PBServerFactory(root_obj))
 reactor.run() reactor.run()
 </file> </file>
  
-<code bash> +<file python pb4client.py> 
-Lancement du serveur $ python3 pb1server.py  +""" 
-returning a Two called <__main__.Two object at 0x7fd4aacfb128> +Client: Echange bidirectionnel serveur client 
-Two.three was given 12+""" 
 +from twisted.internet import reactor 
 +from twisted.spread import pb
  
-Lancement du client $ python3 pb1client.py  +class Two(pb.Referenceable): 
-got first object: <twisted.spread.pb.RemoteReference object at 0x7f00e4c76a90> +    def remote_print(self, arg): 
-asking it to getTwo +        print(f"Two.print() appelé par le serveur avec l'argument: {arg}") 
-got second object: <twisted.spread.pb.RemoteReference object at 0x7f00e4c76b00> +        print(arg) 
-telling it to do three(12) + 
-</code>+class Foo: 
 +    """Permet de créer l'objet principal client qui tourne""" 
 +    def __init__(self): 
 +        """self.root_obj_client sera l'objet principal du serveur root_obj""" 
 +        self.root_obj_client = None 
 +    def step1(self, obj): 
 +        self.root_obj_client = obj 
 +        obj_server = self.root_obj_client.callRemote("getObject") 
 +        print(f"Le client a accès à: {obj_server}") 
 +        obj_server.addCallback(self.step2) 
 +    def step2(self, client_accessible): 
 +        print(f"Got object from server: {client_accessible}") 
 +        print(f"Giving it back to server: {self.root_obj_client}") 
 +        self.root_obj_client.callRemote("checkObject", client_accessible) 
 + 
 +def got_obj(obj, two): 
 +    print("J'ai eu l'objet:", obj) 
 +    print(f"Je lui donne le mien {two}") 
 +    obj.callRemote("takeTwo", two) 
 +def main(): 
 +    foo = Foo() 
 +    two = Two() 
 +    factory = pb.PBClientFactory() 
 +    reactor.connectTCP("localhost", 8800, factory) 
 +    factory.getRootObject().addCallback(foo.step1) 
 +    def1 = factory.getRootObject() 
 +    def1.addCallback(got_obj, two)  # hands our 'two' to the callback 
 +    reactor.run() 
 +main() 
 +</file> 
 +=====Exemple 5: Un vrai client/serveur===== 
 +Le serveur tourne.\\ 
 +Dans une boucle, le client récupére des infos sur le serveur, et lui envoie lui aussi des valeurs. 
 + 
 +<file python pb5server.py> 
 + 
 +from time import sleep 
 +from threading import Thread 
 + 
 +from twisted.internet import reactor 
 +from twisted.spread import pb 
 + 
 +class PlayerSimulator(pb.Referenceable): 
 +    """Cette class permet de créer un objet à partager. 
 +    Il simule un player avec: 
 +        - une position de lecture du fichier musical à self.position 
 +        - un track à lire imposé par le client 
 +    L'objet accessible par le client est player 
 +    """ 
 +    def __init__(self): 
 +        self.track = 1 
 +        self.position = 0 
 +        Thread(target=self.thread_update_position).start() 
 + 
 +    def thread_update_position(self): 
 +        n = 0 
 +        while n < 1000: 
 +            n += 1 
 +            self.position += 1 
 +            sleep(1) 
 + 
 +    def remote_newTrack(self, track): 
 +        """New Track imposé par le client""" 
 +        self.track = track 
 +        print(f"Nouveau track demandé par le client {self.track}") 
 + 
 +class ObjetPrincipal(pb.Root): 
 +    def __init__(self, player): 
 +        self.player = player 
 + 
 +    def remote_getPlayerSimulator(self): 
 +        print(f"Le client  demande self.player, je lui retourne") 
 +        return self.player 
 + 
 +    def remote_getPosition(self): 
 +        p = self.player.position 
 +        print(f"Le serveur envoie au client la position {p}") 
 +        return p 
 + 
 +# un object auquel le client pourra accéder 
 +player = PlayerSimulator() 
 + 
 +# L'objet principal réseau qui tourne 
 +root_obj = ObjetPrincipal(player) 
 + 
 +reactor.listenTCP(8800, pb.PBServerFactory(root_obj)) 
 +reactor.run() 
 +</file> 
 + 
 +<file python pb5client.py> 
 +from time import sleep 
 +from threading import Thread 
 + 
 +from twisted.internet import reactor 
 +# Interaction réseau en TCP 
 +from twisted.spread import pb  # Perspetive Broker de Twisted 
 + 
 +class Client: 
 +    """Permet de créer l'objet principal client qui tourne""" 
 + 
 +    def __init__(self): 
 +        """self.root_obj_client sera l'objet principal du serveur root_obj""" 
 +        self.root_obj_client = None 
 +        self.track = 1 
 + 
 +    def on_start(self, obj): 
 +        print(f"on_start: got client_accessible object from server = {obj}") 
 +        self.root_obj_client = obj 
 +        # Appel du Player sur le serveur et ajout du callback 
 +        self.root_obj_client.callRemote("getPlayerSimulator").addCallback(self.run) 
 + 
 +    def run(self, args): 
 +        Thread(target=self.thread_run).start() 
 + 
 +    def thread_run(self): 
 +        n = 0 
 +        while n < 500: 
 +            # Position 
 +            n += 1 
 +            self.root_obj_client.callRemote("getPosition").addCallback(self.print_position) 
 + 
 +            # Changement de track tous les 10 
 +            if n % 10 == 2: 
 +                self.track += 1 
 +                self.root_obj_client.callRemote("getPlayerSimulator").addCallback(self.toto) 
 +            sleep(0.3) 
 + 
 +    def toto(self, args): 
 +        print("args:", args) 
 +        print(f"Envoi du track: {self.track}") 
 +        args.callRemote("newTrack", self.track) 
 + 
 + 
 +    def print_position(self, position): 
 +        print(f"Le client a reçu: {position}") 
 + 
 + 
 +def main(): 
 +    clt = Client() 
 +    factory = pb.PBClientFactory() 
 +    reactor.connectTCP("localhost", 8800, factory) 
 +    factory.getRootObject().addCallback(clt.on_start) 
 +    reactor.run() 
 + 
 +main() 
 +</file> 
 + 
 +=====Transfert d'une image ou d'un json===== 
 +On peut transférer n'import quoi mais il faut toujours convertir ses datas en bytes (octets) avant de les envoyer. Et les décoder à la réception. 
 +<file python > 
 +from time import sleep 
 +from threading import Thread 
 + 
 +import numpy as np 
 +import cv2 
 + 
 +from twisted.internet import reactor 
 +from twisted.spread import pb 
 + 
 +class MyImage: 
 +    def __init__(self): 
 +        self.img = cv2.imread('./covers/Fasokan.jpg') 
 +        img = cv2.resize(self.img, (512, 512)) 
 +        encode_param=[int(cv2.IMWRITE_JPEG_QUALITY), 90] 
 +        result, imgencode = cv2.imencode('.jpg', img, encode_param) 
 +        data = np.array(imgencode) 
 +        print(data.shape) 
 +        self.stringData = data.tobytes() 
 + 
 + 
 +class ObjetPrincipal(pb.Root): 
 +    def __init__(self): 
 +        self.mi = MyImage() 
 +    def remote_image(self): 
 +        print("Le serveur envoie une image") 
 +        return self.mi.stringData 
 + 
 +# L'objet principal réseau qui tourne 
 +root_obj = ObjetPrincipal() 
 + 
 +reactor.listenTCP(8800, pb.PBServerFactory(root_obj)) 
 +reactor.run() 
 +</file> 
 + 
 +<file python > 
 +import numpy as np 
 +import cv2 
 +import base64 
 +from twisted.internet import reactor 
 +from twisted.spread import pb 
 + 
 + 
 +class GetImage(pb.Copyable): 
 +    def get_image(self, stringData): 
 +        image = np.asarray(bytearray(stringData), dtype="uint8") 
 +        image = cv2.imdecode(image, cv2.IMREAD_COLOR) 
 +        print(image.shape) 
 +        cv2.imshow('SERVER', image) 
 +        cv2.waitKey(0) 
 +        cv2.destroyAllWindows() 
 + 
 +class RemoteGetImage(pb.RemoteCopy): 
 +    pass 
 + 
 +pb.setUnjellyableForClass(GetImage, RemoteGetImage) 
 + 
 +class Client: 
 +    """Permet de créer l'objet principal client qui tourne""" 
 +    def __init__(self): 
 +        """self.root_obj_client sera l'objet principal du serveur root_obj""" 
 +        self.root_obj_client = None 
 +        self.gi = GetImage() 
 +    def on_start(self, obj): 
 +        print(f"on_start: got client_accessible object from server = {obj}") 
 +        self.root_obj_client = obj 
 +        # Transfert d'une image 
 +        self.root_obj_client.callRemote("image").addCallback(self.gi.get_image) 
 +         
 +def main(): 
 +    clt = Client() 
 +    factory = pb.PBClientFactory() 
 +    reactor.connectTCP("localhost", 8800, factory) 
 +    factory.getRootObject().addCallback(clt.on_start) 
 +    reactor.run() 
 + 
 +main() 
 +</file>
  
 +=====Page suivante: Passing Complex Types=====
 +  * **[[pb_copyable_passing_complex_types|PB Copyable Passing Complex Types]]**
  
 {{tag>python sb intergalactique twisted perspectivebroker}} {{tag>python sb intergalactique twisted perspectivebroker}}
using_perspective_broker.1669657705.txt.gz · Dernière modification : de serge