asyncore — Asynchronous socket handler

Source code:Lib/asyncore.py

Deprecated since version 3.6:asyncore will be removed in Python 3.12(seePEP 594 for details).Please useasyncio instead.


Note

This module exists for backwards compatibility only. For new code werecommend usingasyncio.

This module provides the basic infrastructure for writing asynchronous socketservice clients and servers.

There are only two ways to have a program on a single processor do “more thanone thing at a time.” Multi-threaded programming is the simplest and mostpopular way to do it, but there is another very different technique, that letsyou have nearly all the advantages of multi-threading, without actually usingmultiple threads. It’s really only practical if your program is largely I/Obound. If your program is processor bound, then pre-emptive scheduled threadsare probably what you really need. Network servers are rarely processorbound, however.

If your operating system supports theselect() system call in its I/Olibrary (and nearly all do), then you can use it to juggle multiplecommunication channels at once; doing other work while your I/O is takingplace in the “background.” Although this strategy can seem strange andcomplex, especially at first, it is in many ways easier to understand andcontrol than multi-threaded programming. Theasyncore module solvesmany of the difficult problems for you, making the task of buildingsophisticated high-performance network servers and clients a snap. For“conversational” applications and protocols the companionasynchatmodule is invaluable.

The basic idea behind both modules is to create one or more networkchannels, instances of classasyncore.dispatcher andasynchat.async_chat. Creating the channels adds them to a globalmap, used by theloop() function if you do not provide it with your ownmap.

Once the initial channel(s) is(are) created, calling theloop() functionactivates channel service, which continues until the last channel (includingany that have been added to the map during asynchronous service) is closed.

asyncore.loop([timeout[,use_poll[,map[,count]]]])

Enter a polling loop that terminates after count passes or all openchannels have been closed. All arguments are optional. Thecountparameter defaults toNone, resulting in the loop terminating only when allchannels have been closed. Thetimeout argument sets the timeoutparameter for the appropriateselect() orpoll()call, measured in seconds; the default is 30 seconds. Theuse_pollparameter, if true, indicates thatpoll() should be used inpreference toselect() (the default isFalse).

Themap parameter is a dictionary whose items are the channels to watch.As channels are closed they are deleted from their map. Ifmap isomitted, a global map is used. Channels (instances ofasyncore.dispatcher,asynchat.async_chat and subclassesthereof) can freely be mixed in the map.

classasyncore.dispatcher

Thedispatcher class is a thin wrapper around a low-level socketobject. To make it more useful, it has a few methods for event-handlingwhich are called from the asynchronous loop. Otherwise, it can be treatedas a normal non-blocking socket object.

The firing of low-level events at certain times or in certain connectionstates tells the asynchronous loop that certain higher-level events havetaken place. For example, if we have asked for a socket to connect toanother host, we know that the connection has been made when the socketbecomes writable for the first time (at this point you know that you maywrite to it with the expectation of success). The implied higher-levelevents are:

Event

Description

handle_connect()

Implied by the first read or writeevent

handle_close()

Implied by a read event with no dataavailable

handle_accepted()

Implied by a read event on a listeningsocket

During asynchronous processing, each mapped channel’sreadable() andwritable() methods are used to determine whether the channel’s socketshould be added to the list of channelsselect()ed orpoll()ed for read and write events.

Thus, the set of channel events is larger than the basic socket events. Thefull set of methods that can be overridden in your subclass follows:

handle_read()

Called when the asynchronous loop detects that aread() call on thechannel’s socket will succeed.

handle_write()

Called when the asynchronous loop detects that a writable socket can bewritten. Often this method will implement the necessary buffering forperformance. For example:

defhandle_write(self):sent=self.send(self.buffer)self.buffer=self.buffer[sent:]
handle_expt()

Called when there is out of band (OOB) data for a socket connection. Thiswill almost never happen, as OOB is tenuously supported and rarely used.

handle_connect()

Called when the active opener’s socket actually makes a connection. Mightsend a “welcome” banner, or initiate a protocol negotiation with theremote endpoint, for example.

handle_close()

Called when the socket is closed.

handle_error()

Called when an exception is raised and not otherwise handled. The defaultversion prints a condensed traceback.

handle_accept()

Called on listening channels (passive openers) when a connection can beestablished with a new remote endpoint that has issued aconnect()call for the local endpoint. Deprecated in version 3.2; usehandle_accepted() instead.

Deprecated since version 3.2.

handle_accepted(sock,addr)

Called on listening channels (passive openers) when a connection has beenestablished with a new remote endpoint that has issued aconnect()call for the local endpoint.sock is anew socket object usable tosend and receive data on the connection, andaddr is the addressbound to the socket on the other end of the connection.

New in version 3.2.

readable()

Called each time around the asynchronous loop to determine whether achannel’s socket should be added to the list on which read events canoccur. The default method simply returnsTrue, indicating that bydefault, all channels will be interested in read events.

writable()

Called each time around the asynchronous loop to determine whether achannel’s socket should be added to the list on which write events canoccur. The default method simply returnsTrue, indicating that bydefault, all channels will be interested in write events.

In addition, each channel delegates or extends many of the socket methods.Most of these are nearly identical to their socket partners.

create_socket(family=socket.AF_INET,type=socket.SOCK_STREAM)

This is identical to the creation of a normal socket, and will use thesame options for creation. Refer to thesocket documentation forinformation on creating sockets.

Changed in version 3.3:family andtype arguments can be omitted.

connect(address)

As with the normal socket object,address is a tuple with the firstelement the host to connect to, and the second the port number.

send(data)

Senddata to the remote end-point of the socket.

recv(buffer_size)

Read at mostbuffer_size bytes from the socket’s remote end-point. Anempty bytes object implies that the channel has been closed from theother end.

Note thatrecv() may raiseBlockingIOError , even thoughselect.select() orselect.poll() has reported the socketready for reading.

listen(backlog)

Listen for connections made to the socket. Thebacklog argumentspecifies the maximum number of queued connections and should be at least1; the maximum value is system-dependent (usually 5).

bind(address)

Bind the socket toaddress. The socket must not already be bound. (Theformat ofaddress depends on the address family — refer to thesocket documentation for more information.) To markthe socket as re-usable (setting theSO_REUSEADDR option), callthedispatcher object’sset_reuse_addr() method.

accept()

Accept a connection. The socket must be bound to an address and listeningfor connections. The return value can be eitherNone or a pair(conn,address) whereconn is anew socket object usable to sendand receive data on the connection, andaddress is the address bound tothe socket on the other end of the connection.WhenNone is returned it means the connection didn’t take place, inwhich case the server should just ignore this event and keep listeningfor further incoming connections.

close()

Close the socket. All future operations on the socket object will fail.The remote end-point will receive no more data (after queued data isflushed). Sockets are automatically closed when they aregarbage-collected.

classasyncore.dispatcher_with_send

Adispatcher subclass which adds simple buffered output capability,useful for simple clients. For more sophisticated usage useasynchat.async_chat.

classasyncore.file_dispatcher

A file_dispatcher takes a file descriptor orfile object alongwith an optional map argument and wraps it for use with thepoll()orloop() functions. If provided a file object or anything with afileno() method, that method will be called and passed to thefile_wrapper constructor.

Availability: Unix.

classasyncore.file_wrapper

A file_wrapper takes an integer file descriptor and callsos.dup() toduplicate the handle so that the original handle may be closed independentlyof the file_wrapper. This class implements sufficient methods to emulate asocket for use by thefile_dispatcher class.

Availability: Unix.

asyncore Example basic HTTP client

Here is a very basic HTTP client that uses thedispatcher class toimplement its socket handling:

importasyncoreclassHTTPClient(asyncore.dispatcher):def__init__(self,host,path):asyncore.dispatcher.__init__(self)self.create_socket()self.connect((host,80))self.buffer=bytes('GET%s HTTP/1.0\r\nHost:%s\r\n\r\n'%(path,host),'ascii')defhandle_connect(self):passdefhandle_close(self):self.close()defhandle_read(self):print(self.recv(8192))defwritable(self):return(len(self.buffer)>0)defhandle_write(self):sent=self.send(self.buffer)self.buffer=self.buffer[sent:]client=HTTPClient('www.python.org','/')asyncore.loop()

asyncore Example basic echo server

Here is a basic echo server that uses thedispatcher class to acceptconnections and dispatches the incoming connections to a handler:

importasyncoreclassEchoHandler(asyncore.dispatcher_with_send):defhandle_read(self):data=self.recv(8192)ifdata:self.send(data)classEchoServer(asyncore.dispatcher):def__init__(self,host,port):asyncore.dispatcher.__init__(self)self.create_socket()self.set_reuse_addr()self.bind((host,port))self.listen(5)defhandle_accepted(self,sock,addr):print('Incoming connection from%s'%repr(addr))handler=EchoHandler(sock)server=EchoServer('localhost',8080)asyncore.loop()