Asyncore client on stream crashes entire program when sending data immediately

I am writing a simple program in python, with asynchronous and threaded. I want to implement an asynchronous client without blocking anything, for example:

How to handle asyncore inside a python class without blocking anything?

Here is my code:

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")

      

Now the exception will be sent to send ("asfas \ n") because I haven't opened any server.

I think that an exception in the dispatch function will trigger the handle_error function and will not affect the main program, but most of the time it will crash the entire program and sometimes it will work! And if I uncomment time.sleep (5) it crashes the stream. Why is he acting like this? Can I write a program that doesn't crash the whole program and doesn't use time.sleep ()? Thank you! 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

      

-1


source to share


1 answer


First of all, I would suggest not using the old asynchronous module, but looking at more modern and more efficient solutions: gevent or asyncio module transition (Python 3.4), which was somehow transferred to Python 2.

If you want to use asyncore, you need to know:

  • be careful when using sockets created in one thread (the main thread in your case) and sent by another thread (managed by "onethread" in your case), sockets cannot be shared as they are between threads these are not thread safe objects themselves by oneself

  • for the same reason you cannot use the default global map created in the asyncore module, you need to create a map per stream

  • when connecting to the server the connection may not be immediate, you need to wait while it is connected (hence your "sleep 5"). With asyncore, "handle_write" is called when the socket is ready to send data.

Here is a newer version of your code, hopefully it fixes these problems:



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")

      

If you only have 1 socket per stream (e.g. dispatcher map with size 1), no using asyncore at all. Just use a regular, blocking socket in your threads. advantage async i / o comes with a lot of sockets.

EDIT: The answer was edited after comments.

+1


source







All Articles