Fix Issue 6706: return None on connect() in case of EWOULDBLOCK/ECONNABORTED error.
This commit is contained in:
parent
8581c7e11a
commit
5ea3d0f95b
|
@ -209,10 +209,13 @@ any that have been added to the map during asynchronous service) is closed.
|
|||
.. method:: accept()
|
||||
|
||||
Accept a connection. The socket must be bound to an address and listening
|
||||
for connections. The return value is a pair ``(conn, address)`` where
|
||||
*conn* is a *new* socket object usable to send and receive data on the
|
||||
connection, and *address* is the address bound to the socket on the other
|
||||
end of the connection.
|
||||
for connections. The return value can be either ``None`` or a pair
|
||||
``(conn, address)`` where *conn* is a *new* socket object usable to send
|
||||
and receive data on the connection, and *address* is the address bound to
|
||||
the socket on the other end of the connection.
|
||||
When ``None`` is returned it means the connection didn't take place, in
|
||||
which case the server should just ignore this event and keep listening
|
||||
for further incoming connections.
|
||||
|
||||
|
||||
.. method:: close()
|
||||
|
@ -222,6 +225,12 @@ any that have been added to the map during asynchronous service) is closed.
|
|||
flushed). Sockets are automatically closed when they are
|
||||
garbage-collected.
|
||||
|
||||
.. class:: dispatcher_with_send()
|
||||
|
||||
A :class:`dispatcher` subclass which adds simple buffered output capability,
|
||||
useful for simple clients. For more sophisticated usage use
|
||||
:class:`asynchat.async_chat`.
|
||||
|
||||
.. class:: file_dispatcher()
|
||||
|
||||
A file_dispatcher takes a file descriptor or :term:`file object` along
|
||||
|
@ -238,7 +247,7 @@ any that have been added to the map during asynchronous service) is closed.
|
|||
socket for use by the :class:`file_dispatcher` class. Availability: UNIX.
|
||||
|
||||
|
||||
.. _asyncore-example:
|
||||
.. _asyncore-example-1:
|
||||
|
||||
asyncore Example basic HTTP client
|
||||
----------------------------------
|
||||
|
@ -248,7 +257,7 @@ implement its socket handling::
|
|||
|
||||
import asyncore, socket
|
||||
|
||||
class http_client(asyncore.dispatcher):
|
||||
class HTTPClient(asyncore.dispatcher):
|
||||
|
||||
def __init__(self, host, path):
|
||||
asyncore.dispatcher.__init__(self)
|
||||
|
@ -272,6 +281,45 @@ implement its socket handling::
|
|||
sent = self.send(self.buffer)
|
||||
self.buffer = self.buffer[sent:]
|
||||
|
||||
c = http_client('www.python.org', '/')
|
||||
|
||||
asyncore.loop()
|
||||
client = HTTPClient('www.python.org', '/')
|
||||
asyncore.loop()
|
||||
|
||||
.. _asyncore-example-2:
|
||||
|
||||
asyncore Example basic echo server
|
||||
----------------------------------
|
||||
|
||||
Here is abasic echo server that uses the :class:`dispatcher` class to accept
|
||||
connections and dispatches the incoming connections to a handler::
|
||||
|
||||
import asyncore
|
||||
import socket
|
||||
|
||||
class EchoHandler(asyncore.dispatcher_with_send):
|
||||
|
||||
def handle_read(self):
|
||||
data = self.recv(8192)
|
||||
self.send(data)
|
||||
|
||||
class EchoServer(asyncore.dispatcher):
|
||||
|
||||
def __init__(self, host, port):
|
||||
asyncore.dispatcher.__init__(self)
|
||||
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.set_reuse_addr()
|
||||
self.bind((host, port))
|
||||
self.listen(5)
|
||||
|
||||
def handle_accept(self):
|
||||
pair = self.accept()
|
||||
if pair is None:
|
||||
return
|
||||
else:
|
||||
sock, addr = pair
|
||||
print('Incoming connection from %s' % repr(addr))
|
||||
handler = EchoHandler(sock)
|
||||
|
||||
server = EchoServer('localhost', 8080)
|
||||
asyncore.loop()
|
||||
|
||||
|
|
|
@ -346,12 +346,15 @@ class dispatcher:
|
|||
# XXX can return either an address pair or None
|
||||
try:
|
||||
conn, addr = self.socket.accept()
|
||||
return conn, addr
|
||||
except TypeError:
|
||||
return None
|
||||
except socket.error as why:
|
||||
if why.args[0] == EWOULDBLOCK:
|
||||
pass
|
||||
if why.args[0] in (EWOULDBLOCK, ECONNABORTED):
|
||||
return None
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
return conn, addr
|
||||
|
||||
def send(self, data):
|
||||
try:
|
||||
|
|
21
Lib/smtpd.py
21
Lib/smtpd.py
|
@ -297,22 +297,11 @@ class SMTPServer(asyncore.dispatcher):
|
|||
localaddr, remoteaddr), file=DEBUGSTREAM)
|
||||
|
||||
def handle_accept(self):
|
||||
try:
|
||||
conn, addr = self.accept()
|
||||
except TypeError:
|
||||
# sometimes accept() might return None
|
||||
return
|
||||
except socket.error as err:
|
||||
# ECONNABORTED might be thrown
|
||||
if err.args[0] != errno.ECONNABORTED:
|
||||
raise
|
||||
return
|
||||
else:
|
||||
# sometimes addr == None instead of (ip, port)
|
||||
if addr == None:
|
||||
return
|
||||
print('Incoming connection from %s' % repr(addr), file=DEBUGSTREAM)
|
||||
channel = SMTPChannel(self, conn, addr)
|
||||
pair = self.accept()
|
||||
if pair is not None:
|
||||
conn, addr = pair
|
||||
print('Incoming connection from %s' % repr(addr), file=DEBUGSTREAM)
|
||||
channel = SMTPChannel(self, conn, addr)
|
||||
|
||||
# API for "doing something useful with the message"
|
||||
def process_message(self, peer, mailfrom, rcpttos, data):
|
||||
|
|
|
@ -143,6 +143,9 @@ C-API
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue 6706: asyncore accept() method no longer raises EWOULDBLOCK/ECONNABORTED
|
||||
on incomplete connection attempt but returns None instead.
|
||||
|
||||
- Issue #10266: uu.decode didn't close in_file explicitly when it was given
|
||||
as a filename. Patch by Brian Brazil.
|
||||
|
||||
|
|
Loading…
Reference in New Issue