2011-11-26 45 views
0

SocketClientThread参考:http://eli.thegreenplace.net/2011/05/18/code-sample-socket-client-thread-in-python/多个螺纹套接字连接/队列

以利提供了如何管理一个插座客户线程内,并传送到与该队列模块的主要范围这个通用例子。 (再次感谢Eli!)

一个线程工作的很好,但我试图做的是同时管理多个SocketClientThread对象。

连接后,当我尝试发送数据到第二个对象时,它告诉我SocketClientThread.socket没有sendall属性,所以我认为套接字被取消。

1和2的服务器都成功接收连接,但它是触发错误的第二个服务器的发送命令。

如何重新使用这个类与多个对象?

下面是输出:

$ python testmodule.py 
('sct1: ', 1, None) 
('sct1: ', 1, 'tuxy') 
('sct2: ', 1, None) 
Exception in thread Thread-2: 
Traceback (most recent call last): 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/threading.py", line 522, in __bootstrap_inner 
    self.run() 
    File "testmodule.py", line 59, in run 
    self.handlers[cmd.type](cmd) 
    File "testmodule.py", line 115, in _handle_SEND 
    self.socket.sendall(header + cmd.data) 
AttributeError: 'NoneType' object has no attribute 'sendall' 

,这里是试图打开我的两个代码:

if __name__ == "__main__": 
    sct1 = SocketClientThread() 
    sct1.start() 
    sct1.cmd_q.put(ClientCommand(ClientCommand.CONNECT, ('', 50007))) 
    reply = sct1.reply_q.get(True) 
    sct1.cmd_q.put(ClientCommand(ClientCommand.SEND, "hellothere from sct1")) 
    reply = sct1.reply_q.get(True) 
    print('sct1: ', reply.type, reply.data) 
    sct1.cmd_q.put(ClientCommand(ClientCommand.RECEIVE, "hellothere from sct1")) 
    reply = sct1.reply_q.get(True) 
    print('sct1: ', reply.type, reply.data) 

    sct2 = SocketClientThread() 
    sct2.start() 
    sct2.cmd_q.put(ClientCommand(ClientCommand.CONNECT, ('', 50008))) 
    reply = sct2.reply_q.get(True) 
    print('sct2 connect: ', reply.type, reply.data) 
    sct2.cmd_q.put(ClientCommand(ClientCommand.SEND, "hellothere from sct2")) 
    reply = sct2.reply_q.get(True) 
    print('sct2 send: ', reply.type, reply.data) 
    sct2.cmd_q.put(ClientCommand(ClientCommand.RECEIVE, "hellothere from sct2")) 
    reply = sct2.reply_q.get(True) 
    print('sct2: ', reply.type, reply.data) 

    #close connection 1 
    sct1.cmd_q.put(ClientCommand(ClientCommand.CLOSE)) 
    reply = sct1.reply_q.get(True) 
    print('sct1 close: ', reply.type, reply.data) 

    #close connection 2 
    sct2.cmd_q.put(ClientCommand(ClientCommand.CLOSE)) 
    reply = sct2.reply_q.get(True) 
    print('sct2 close: ', reply.type, reply.data) 

回答

2

看起来您已经在示例代码中发现了一个错误:-)只有当您同时创建多个线程时才会发生该错误,如您所注意的。这是因为Queue.Queue()默认参数只在类定义时才构造 - 这实际上是Python中的一个常见错误,但通常发生在列表中。

我已经更新了帖子,但不变的是在这里:

def __init__(self, cmd_q=None, reply_q=None): 
    super(SocketClientThread, self).__init__() 
    self.cmd_q = cmd_q or Queue.Queue() 
    self.reply_q = reply_q or Queue.Queue() 
    self.alive = threading.Event() 
    self.alive.set() 
    self.socket = None 

    self.handlers = { 
     ClientCommand.CONNECT: self._handle_CONNECT, 
     ClientCommand.CLOSE: self._handle_CLOSE, 
     ClientCommand.SEND: self._handle_SEND, 
     ClientCommand.RECEIVE: self._handle_RECEIVE, 
    } 

注意队列如何现在初始化 - 这是一个常见的成语,以避免可变默认参数的疑难杂症。

示例代码现在工作对我来说


附:在我的Windows机器上,我必须在客户端指定主机(即使它是localhost)才能成功连接。

+0

我不能够感谢你。我确认我的套接字和队列现在都按预期工作。队列的创建方式让人想起,但我无法理解如何杀死套接字。我看到他们共享相同的队列对象。谢谢! – Coder1

+0

@ Coder1:是的,所以另一个线程得到了杀死第一个套接字的请求,并且终止了它自己的套接字,但之后得到了发送/接收请求... –

+0

不应该只是能够调用从它的父对象mysocketclientthread.join()终止线程?我已经尝试了这一点,并添加了加入队列处理程序。该应用程序挂起,似乎父对象变得未设置。也许不是一个好评的话题。 – Coder1

0

对于多线程使用套接字线程/进程之间的通信我会建议您尝试ZeroMQ编程。它使异步I/O变得简单,并具有内置的自动排队功能。让多个线程同时向GUI线程发送消息是微不足道的,并且消息在到达时排队并处理。我希望这有帮助。