两个类之间的python线程无法正常工作

时间:2012-02-06 18:39:11

标签: python multithreading

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

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

2 个答案:

答案 0 :(得分:2)

  • 使用global s, host, port是导致问题的原因。在A.py, 例如,服务器和客户端类都在改变 相同变量shostport。通过将端口更改为相同的值,您要么弄乱服务器还是客户端(以先运行的方式)。

    如果您不需要,请不要使用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

答案 1 :(得分:0)

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

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

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