线程中的Asyncore客户端在立即发送数据时使整个程序崩溃

时间:2014-12-10 11:32:38

标签: python multithreading python-multithreading asyncore

我在python中编写了一个简单的程序,使用asyncore和threading。我想实现一个异步客户端而不阻塞任何东西,比如:

How to handle asyncore within a class in python, without blocking anything?

这是我的代码:

import socket, threading, time, asyncore
class Client(asyncore.dispatcher):
    def __init__(self, host, port):
        asyncore.dispatcher.__init__(self)
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.connect((host, port))
mysocket = Client("",8888)
onethread = threading.Thread(target=asyncore.loop)
onethread.start()
# time.sleep(5)
mysocket.send("asfas\n")
input("End")

现在异常将被发送到send(" asfas \ n"),因为我没有打开任何服务器。

我认为send函数中的异常将调用handle_error函数并且不会影响主程序,但大多数时候它会崩溃整个程序,有时它会起作用!如果我取消注释time.sleep(5),它只会使线程崩溃。为什么它会像这样?我可以编写一个不会使整个程序崩溃并且不使用time.sleep()的程序吗?谢谢! 错误讯息:

Traceback (most recent call last):
  File "thread.py", line 13, in <module>
    mysocket.send("asfas\n")
  File "/usr/lib/python2.7/asyncore.py", line 374, in send
    result = self.socket.send(data)
socket.error: [Errno 111] Connection refused

1 个答案:

答案 0 :(得分:1)

首先,我建议不要使用旧的asyncore模块,而是要考虑更多 现代和更有效的解决方案:gevent,或者沿着asyncio模块(Python 3.4), 已经以某种方式向Python 2反向移植。

如果你想使用asyncore,那么你必须知道:

  • 使用在一个线程(主线程,在你的情况下)中创建的套接字并由另一个线程调度(在你的情况下由“onethread”管理)时要小心,线程之间不能像这样共享套接字它本身不是线程安全的对象

  • 出于同样的原因,您无法使用asyncore模块中默认创建的全局地图,您必须按线程创建地图

  • 连接到服务器时,连接可能不是立即连接,您必须等待它连接(因此您的“睡眠5”)。使用asyncore时,会调用“handle_write” socket已准备好发送数据。

以下是您的代码的较新版本,希望它能解决这些问题:

import socket, threading, time, asyncore

class Client(threading.Thread, asyncore.dispatcher):
    def __init__(self, host, port):
        threading.Thread.__init__(self)
        self.daemon = True
        self._thread_sockets = dict()
        asyncore.dispatcher.__init__(self, map=self._thread_sockets)

        self.host = host
        self.port = port
        self.output_buffer = []
        self.start()

    def run(self):
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.connect((self.host, self.port))
        asyncore.loop(map=self._thread_sockets)

    def send(self, data):
        self.output_buffer.append(data)

    def handle_write(self):
        all_data = "".join(self.output_buffer)
        bytes_sent = self.socket.send(all_data)
        remaining_data = all_data[bytes_sent:]
        self.output_buffer = [remaining_data]

mysocket = Client("",8888)
mysocket.send("asfas\n")

如果你的线程只有1个套接字(即调度程序的大小为1的地图),则没有 完全使用asyncore。只需在线程中使用普通的阻塞套接字即可。该 async i / o的好处是有很多套接字。

编辑:答案已在评论后进行了编辑。