2012-02-06 59 views
1

我已经写了这两个.py代码来进行每个outher之间的通信。 A.py监听端口8888并将数据发送到7777 B.py监听端口7777并将数据发送到8888 这两个客户端部分在启动服务器后都陷入无限循环。 问题在哪里? 如果我只使用A.py中的服务器和B.py中使用的客户端(反之亦然),而没有使用任何线程,则它们工作正常。两个类之间的python线程无法正常工作

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

哪里有客户端部分运行呢? – Sid 2012-02-06 18:57:52

回答

2
  • 使用global s, host, port是导致问题的原因。在A.py中,例如, ,服务器和客户机类别都在更改 相同的变量s,hostport。通过将端口更改为相同的值,您可能会搞乱服务器或客户端(以先运行的为准)。

    如果您不需要,绝不要使用global,而且您很少必须使用。 在这种情况下,您的问题通过使用实例属性得到解决。

  • 此外,我建议编写client.run方法,而不递归 调用self.run()。 Python对可以进行多少次递归调用 有限制,如果客户端需要等待太久,则在这里调用递归调用 可能会导致程序失败。相反,您可以使用 while循环。 (见下文)。

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

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

:)谢谢..很好的回复 – qmaruf 2012-02-06 19:33:25

0

我有一种感觉你的问题,至少部分是由Python的Global Interpreter Lock,这限制了CPython的解释器来执行的字节码引起的在一个单一的线程。所以,即使您的脚本使用多个线程,一次只能执行其中的一个线程。程序挂起的原因是因为服务器实例在等待输入时阻塞,所以它永远不会释放GIL,从而阻止客户端发送数据。

幸运的是,有几个解决方法:
- 使用Python的multiprocessing包,让您的程序使用进程而不是线程。因为无论如何你都在使用TCP套接字在你的类之间共享数据,所以这应该是一个最小的代码改变。
- IronPythonJython在他们的实现中不使用GIL,所以如果你有心使用线程而不是进程,你可能想要调查其中的一个项目。

如果您有兴趣,David Beazley几年前创建了interesting presentation about the GIL

+0

当你阻止等待输入时,GIL应该实际释放。 – lunixbochs 2012-02-06 19:04:51