2012-02-06 4 views
1

J'ai écrit ce code .py pour communiquer entre chaque sortie. A.py écoute le port 8888 et envoie les données à 7777 B.py écoute le port 7777 et envoie les données à 8888 Ces deux parties client sont bloquées dans une boucle infinie après le démarrage de leur serveur. où est le problème ?? Si je n'utilise que le serveur dans A.py et le client dans B.py (et vice versa) sans aucun thread, ils fonctionnent correctement.Le threading python entre deux classes ne fonctionne pas correctement

A.py:

import socket  
import threading 
import thread 
import time 


class server(threading.Thread): 
    s = '' 
    host = 0 
    port = 0 
    def __init__(self): 
     threading.Thread.__init__(self) 
     global s,host,port 
     s = socket.socket()   
     host = socket.gethostname() 
     port = 8888 

    def run(self): 
     global s,host,port 
     print 'Server started!' 
     print 'Waiting for clients...' 

     s.bind((host, port))  
     s.listen(5)     
     c, addr = s.accept()  
     print 'Got connection from', addr 
     while True: 
      time.sleep(2) 
      msg = c.recv(1024) 
      if len(msg)==0 : break 
      print addr, ' >> ', msg 




class client(threading.Thread): 
    s = '' 
    host = 0 
    port = 0 

    def __init__(self): 
     threading.Thread.__init__(self) 
     global s,host,port 
     s = socket.socket()   
     host = socket.gethostname() 
     port = 7777 

    def run(self): 

     try: 
      time.sleep(5) 
      global s,host,port 
      print 'Connecting to ', host, port 
      s.connect((host, port)) 
      print "Connectd" 
      while True: 
       time.sleep(2) 
       msg = raw_input('CLIENT >> ') 
       if len(msg)==0:break 
       s.send(msg) 
     except: 
      print "Waiting" 
      self.run() 



thread1 = server() 
thread2 = client(); 

thread1.start() 
thread2.start() 

thread1.join() 
thread2.join(); 

B.py:

import socket  
import threading 
import thread 
import time 


class server(threading.Thread): 
    s = '' 
    host = 0 
    port = 0 
    def __init__(self): 
     threading.Thread.__init__(self) 
     global s,host,port 
     s = socket.socket()   
     host = socket.gethostname() 
     port = 7777 

    def run(self): 
     global s,host,port 
     print 'Server started!' 
     print 'Waiting for clients...' 

     s.bind((host, port))  
     s.listen(5)     
     c, addr = s.accept()  
     print 'Got connection from', addr 
     while True: 
      time.sleep(2) 
      msg = c.recv(1024) 
      if len(msg)==0 : break 
      print addr, ' >> ', msg 



class client(threading.Thread): 
    s = '' 
    host = 0 
    port = 0 

    def __init__(self): 
     threading.Thread.__init__(self) 
     global s,host,port 
     s = socket.socket()   
     host = socket.gethostname() 
     port = 8888 

    def run(self): 
     try: 
      time.sleep(5) 
      global s,host,port 
      print 'Connecting to ', host, port 
      s.connect((host, port)) 
      print "connected" 
      while True: 
       time.sleep(2) 
       msg = raw_input('CLIENT >> ') 
       if len(msg)==0:break 
       s.send(msg) 
     except: 
      print "waiting" 
      self.run(); 



thread1 = server() 
thread2 = client(); 

thread1.start() 
thread2.start() 

thread1.join() 
thread2.join(); 
+1

Où sont les pièces du client? – Sid

Répondre

2
  • L'utilisation de global s, host, port est à l'origine du problème. Dans A.py, par exemple, les classes serveur et client modifient les mêmes variables s, host et port. En changeant le port pour avoir la même valeur, vous êtes en train de bousiller le serveur ou le client (celui qui s'exécute en premier).

    N'utilisez jamais global si ce n'est pas obligatoire, et vous avez très rarement à le faire. Dans ce cas, votre problème est résolu en utilisant les attributs d'instance.

  • En outre, je suggère d'écrire la méthode client.run sans appels récursifs à self.run(). Python a une limite à combien d'appels récursifs vous pouvez faire, et si le client doit attendre trop longtemps, un appel récursif ici pourrait provoquer l'échec de votre programme. Au lieu de cela, vous pouvez utiliser une boucle while. (Voir ci-dessous).

import argparse 
import socket  
import threading 
import thread 
import time 

class server(threading.Thread): 
    def __init__(self, port): 
     threading.Thread.__init__(self) 
     self.s = socket.socket()   
     self.host = socket.gethostname() 
     self.port = port 

    def run(self): 
     print 'Server started!' 
     print 'Waiting for clients...' 

     self.s.bind((self.host, self.port))  
     self.s.listen(5)     
     c, addr = self.s.accept()  
     print 'Got connection from', addr 
     while True: 
      time.sleep(2) 
      msg = c.recv(1024) 
      if len(msg) == 0 : break 
      print addr, ' >> ', msg 

class client(threading.Thread): 
    def __init__(self, port): 
     threading.Thread.__init__(self) 
     self.s = socket.socket()   
     self.host = socket.gethostname() 
     self.port = port 

    def run(self): 
     while True: 
      time.sleep(5) 
      print 'Connecting to ', self.host, self.port 
      try: 
       self.s.connect((self.host, self.port)) 
       break 
      except Exception as err: 
       print "Waiting", err 
     print "Connectd" 
     while True: 
      time.sleep(2) 
      msg = raw_input('CLIENT >> ') 
      if len(msg) == 0:break 
      self.s.send(msg) 

if __name__ == '__main__': 
    parser = argparse.ArgumentParser() 
    parser.add_argument('--server_port', type = int, default = 8888) 
    parser.add_argument('--client_port', type = int, default = 7777) 
    args = parser.parse_args() 

    thread1 = server(args.server_port) 
    thread2 = client(args.client_port) 

    thread1.start() 
    thread2.start() 

    thread1.join() 
    thread2.join() 

Exécuter avec

test.py --server 8888 --client 7777 
test.py --server 7777 --client 8888 
+0

:) Merci .. Réponse merveilleuse – qmaruf

0

Je sens votre problème est causé au moins en partie par Python Global Interpreter Lock, ce qui limite un interprète CPython à exécuter bytecode sur un seul fil. Ainsi, même si votre script utilise plusieurs threads, un seul d'entre eux peut s'exécuter à la fois. La raison pour laquelle votre programme se bloque est que votre instance de serveur bloque en attendant l'entrée, de sorte qu'elle ne libère jamais le GIL, empêchant ainsi le client d'envoyer des données.

Heureusement pour vous, il y a des solutions de contournement couple:
- Utiliser package multiprocessing Python, que vos processus d'utilisation du programme au lieu de threads. Parce que vous partagez des données entre vos classes en utilisant des sockets TCP de toute façon, cela devrait être un changement de code minimal.
- IronPython et Jython ne pas utiliser un GIL dans leurs implémentations, donc si vous avez votre cœur à utiliser des threads au lieu de processus, vous pouvez vouloir étudier un de ces projets.

Si cela vous intéresse, David Beazley a créé un interesting presentation about the GIL il y a quelques années.

+0

le GIL devrait réellement libérer quand vous bloquez pour attendre l'entrée. – lunixbochs

Questions connexes