« Programmation Python/Threads » : différence entre les versions

Contenu supprimé Contenu ajouté
Aucun résumé des modifications
Ligne 484 :
La classe <code>ThreadConnexion()</code> ci-dessous sert à instancier la série d'objets threads qui s'occuperont en parallèle de toutes les connexions lancées par les clients. Sa méthode <code>run()</code> contient la fonctionnalité centrale du serveur, à savoir la boucle d'instructions qui gère la réception des messages provenant d'un client particulier, lesquels entraînent chacun toute une cascade de réactions. Vous y trouverez la mise en oeuvre concrète du protocole de communication décrit dans les pages précédentes (certains messages étant cependant générés par les méthodes <code>depl_aleat_canon()</code> et <code>goal()</code> de la classe <code>AppServeur()</code> décrite plus loin).
 
<source lang=python line start=58>
{{todo|num à droite}}
 
58.class ThreadConnexion(threading.Thread):
<pre>
59. """objet thread gestionnaire d'une connexion client"""
58.class ThreadConnexion(threading.Thread):
def __init__(self, boss, conn):
59. """objet thread gestionnaire d'une connexion client"""
60. def threading.Thread.__init__(self, boss, conn):
63. self.appconnexion = boss conn # réf. dedu lasocket fenêtrede applicationconnexion
61. threading.Thread.__init__(self)
62. self.connexionapp = connboss # réf. dude socketla defenêtre connexionapplication
 
63. self.app = boss # réf. de la fenêtre application
65. def run(self):
64.
"actions entreprises en réponse aux messages reçus du client"
65. def run(self):
66. "actionsnom entreprises= enself.getName() réponse aux messages reçus # id. du client" = nom du thread
68. while 1:
67. nom = self.getName() # id. du client = nom du thread
msgClient = self.connexion.recv(1024)
68. while 1:
69. msgClientprint ="**%s** de %s" % self.connexion.recv(1024msgClient, nom)
70. printdeb "**%s** de %s" %= msgClient.split(msgClient', nom')[0]
71. if deb == msgClient.split(',')[0]"fin" or deb =="":
72. if deb == "fin" or deb =="":self.app.enlever_canon(nom)
73. self.app.enlever_canon(nom)# signaler le départ de ce canon aux autres clients :
74. # signaler le départ de ce canon aux autres clients :self.app.verrou.acquire()
75. for cli in self.app.verrou.acquire()conn_client:
76. for if cli in!= self.app.conn_clientnom:
77. if cli ! message = "départ_de,%s" % nom:
78. self.app.conn_client[cli].send(message = "départ_de,%s" % nom)
79. self.app.verrou.release() self.app.conn_client[cli].send(message)
80. self.app.verrou.release() # fermer le présent thread :
81. #break fermer le présent thread :
82. break elif deb =="client OK":
83. elif deb ==" # signaler au nouveau client OK"les canons déjà enregistrés :
84. # signaler au nouveau client lesmsg ="canons déjà enregistrés :,"
85. msgfor ="canons,"g in self.app.guns:
86. for g in gun = self.app.guns:[g]
87. gunmsg =msg self.app.guns[g]+"%s;%s;%s;%s;%s," % \
88. msg =msg +"%s;%s;%s;%s;%s (gun.id," %gun.x1, \gun.y1, gun.sens, gun.coul)
89. (gunself.id, gunapp.x1, gunverrou.y1, gun.sens, gun.coulacquire()
90. self.app.verrouconnexion.acquiresend(msg)
91. self.connexion.send# attendre un accusé de réception (msg'OK') :
92. # attendre un accusé de réception self.connexion.recv('OK'100) :
93. self.connexionapp.recvverrou.release(100)
94. self.app.verrou.release() # ajouter un canon dans l'espace de jeu serveur.
95. # ajouterla unméthode canoninvoquée dansrenvoie l'espaceles decaract. jeudu serveur.canon créé :
96. #x, lay, méthodesens, invoquéecoul renvoie= les caractself. du canon créé :app.ajouter_canon(nom)
97. x,# y,signaler sens,les coulcaract. =de self.app.ajouter_canon(nom)ce nouveau canon à tous les
98. # signalerclients lesdéjà caract.connectés de ce nouveau canon à tous les:
99. # clients déjà connectés :self.app.verrou.acquire()
100. for cli in self.app.verrou.acquire()conn_client:
101. for cli in self.app.conn_client: msg ="nouveau_canon,%s,%s,%s,%s,%s" % \
102. msg ="nouveau_canon (nom,%s x,%s y,%s,%s,%s" %sens, \coul)
103. # pour le nouveau (nomclient, x,ajouter y,un sens,champ coul)indiquant
104. # pourque le nouveaumessage client,concerne ajouterson unpropre champcanon indiquant:
105. #if quecli le message concerne son propre canon== nom:
106. if cli msg ==msg nom:+",le_vôtre"
107. self.app.conn_client[cli].send(msg =msg +",le_vôtre")
108. self.app.conn_client[cli]verrou.sendrelease(msg)
109. elif deb self.app.verrou.release()=='feu':
110. elif deb =='feu': self.app.tir_canon(nom)
111. self.app.tir_canon(nom)# Signaler ce tir à tous les autres clients :
112. # Signaler ce tir à tous les autres clients :self.app.verrou.acquire()
113. for cli in self.app.verrou.acquire()conn_client:
114. for if cli in!= self.app.conn_clientnom:
115. if cli ! message = "tir_de,%s," % nom:
116. self.app.conn_client[cli].send(message) = "tir_de,%s," % nom
117. self.app.conn_client[cli]verrou.sendrelease(message)
118. elif deb self.app.verrou.release()=="orienter":
119. elif deb t =="orienter":msgClient.split(',')
120. t# =msgClienton peut avoir reçu plusieurs angles.split(',') utiliser le dernier:
122. self.app.orienter_canon(nom, t[-2])
121. # on peut avoir reçu plusieurs angles. utiliser le dernier:
# Signaler ce changement à tous les autres clients :
122. self.app.orienter_canon(nom, t[-2])
123. # Signaler ce changement à tous les autres clients :self.app.verrou.acquire()
124. for cli in self.app.verrou.acquire()conn_client:
125. for if cli in!= self.app.conn_clientnom:
126. if cli != nom # virgule terminale, car messages parfois groupés :
127. #message virgule= terminale"angle,%s,%s," car% messages parfois groupés(nom, :t[-2])
128. message = "angle,%s,%s," % (nom, tself.app.conn_client[-2cli].send(message)
129. self.app.conn_client[cli]verrou.sendrelease(message)
130. self.app.verrou.release()
131. # Fermeture de la connexion :
132 self.connexion.close() # Fermeture de# couper la connexion :
133. del self.connexionapp.close()conn_client[nom] # suppr. sa réf. dans le # couper la connexiondictionn.
134. del self.app.conn_client[nom]afficher("Client %s # supprdéconnecté.\n" sa% réf. dans le dictionn.nom)
136. # Le thread se termine ici
135. self.app.afficher("Client %s déconnecté.\n" % nom)
</source>
136. # Le thread se termine ici
137.
</pre>
 
=== Synchronisation de threads concurrents à l'aide de « verrous » (thread locks) ===