本文介绍了线程中的异步客户端在立即发送数据时使整个程序崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用 python 编写了一个简单的程序,带有异步和线程.我想在不阻塞任何东西的情况下实现异步客户端,如下所示:

I write a simple program in python, with asyncore and threading. I want to implement a asynchorous client without blocking anything, like this:

如何在内部处理异步python中的一个类,没有阻塞任何东西?

这是我的代码:

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")会抛出异常,因为我没有打开任何服务器.

Now a exception will be throwed in send("asfas\n"), because I didn't open any server.

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

I think the exception in send function will call the handle_error function and won't affect the main program, but most of the time it crashes the whole program, and sometimes it works! And if I uncomment the time.sleep(5), it will only crash the thread. Why does it behave like this? Could I write a program that won't crash the whole program and don't use time.sleep() ? Thanks!Error message:

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

推荐答案

首先,我建议不要使用旧的 asyncore 模块,而是查看更多现代和更有效的解决方案:gevent,或者使用 asyncio 模块 (Python 3.4),已以某种方式向后移植到 Python 2.

First of all, I would suggest not using the old asyncore module but to look into moremodern and more efficient solutions: gevent, or going along the asyncio module (Python 3.4),which has been backported somehow to Python 2.

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

If you want to use asyncore, then you have to know:

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

  • be careful when using sockets created in one thread (the main thread, in your case), and dispatched by another thread (managed by "onethread", in your case), sockets cannot be shared like this between threads it is not threadsafe objects by themselves

同理,asyncore 模块中默认创建的全局映射不能使用,必须通过线程创建映射

for the same reason, you can't use the global map created by default in asyncore module, you have to create a map by thread

连接到服务器时,连接可能不是立即的,您必须等待它连接(因此您的睡眠 5").使用 asyncore 时,handle_write"在以下情况下被调用套接字已准备好发送数据.

when connecting to a server, connection may not be immediate you have to wait for it to be connected (hence your "sleep 5"). When using asyncore, "handle_write" is called whensocket is ready to send data.

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

Here is a newer version of your code, hopefully it fixes those issues:

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 的调度员映射),则没有点使用异步.只需在线程中使用普通的阻塞套接字即可.这异步 i/o 的好处是有很多套接字.

If you have only 1 socket by thread (i.e a dispatcher's map with size 1), there is nopoint using asyncore at all. Just use a normal, blocking socket in your threads. Thebenefit of async i/o comes with a lot of sockets.

EDIT:已根据评论对答案进行编辑.

EDIT: answer has been edited following comments.

这篇关于线程中的异步客户端在立即发送数据时使整个程序崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

05-26 05:33
查看更多