多线程套接字连接/队列

时间:2011-11-26 22:46:45

标签: python

SocketClientThread参考:http://eli.thegreenplace.net/2011/05/18/code-sample-socket-client-thread-in-python/

Eli提供了如何在线程内管理套接字客户端以及使用Queue模块与主作用域通信的通用示例。 (再次感谢Eli!)

一个线程运行良好,但我想做的是同时管理多个SocketClientThread对象。

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

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

如何在多个对象中重复使用此类?

这是输出:

$ 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 个答案:

答案 0 :(得分: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,
    }

注意队列现在是如何初始化的 - 这是避免可变默认参数getcha的常用习惯用法。

您的示例代码现在适用于我


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

答案 1 :(得分:0)

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