Normally when youmake a nonblockingconnect, socket gets EINPROGRESS, later the result of this request will appear after select returns.
I think asyncore/asynchat incorrectly interprets asychronous connects. Reading Steven's book, I did some modifications to asyncore.dispatcher and asynchat.async_chat asbelow to correctly interpret errors like: ECONNREFUSED, ETIMEDOUT, ENETUNREACH, EHOSTUNREACH, ENETDOWN. Then I used my custom base classes. In the code below I only show the approach for this situation. I have other modifications for other problems (infinte recursions etc.) but those are not shown here.
The reason is that when a socket connection makes connect, the descriptor becomes both readable and writable at the same time if there is a problem in connect. However, asyncore polling mechanism gets readable ready and writable ready separately. Therefore, it cannot detect connect errors. If you consider writability as a healthy condition (incorrectly) you would try to write without a connection establishment, this gives some other error but not the actual error, in handle_error().
Full discussion ofnonblocking connects can be found in chapter 16 of the book UNIX Network Programming Volume 1, Third Edition The Sockets Networking API, W. Richard Stevens, Bill Fenner, Andrew M. Rudoff
Here is my approach:
# drive from asyncore.dispatcher:
class base_channel(asyncore.dispatcher):
def handle_read_event(self): if self.accepting: if not self.connected: self.connected = 1 self.handle_accept() elif not self.connected:
self.handle_connect_event() else: self.handle_read()
def handle_write_event(self): if not self.connected: self.handle_connect_event() else: self.handle_write()
def handle_connect_event(self): err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) if err: raise socket.error, (err, os.strerror(err)) self.connected
= 1 self.handle_connect()
# I mix the above base_channel
class base_chatter(base_channel, asynchat.async_chat):
def __init__ (self, conn=None):
base_channel.__init__(self, conn)
self.ac_in_buffer = '' self.ac_out_buffer = '' self.producer_fifo = asynchat.fifo()
def handle_close(self): asynchat.async_chat.handle_close(self)
def handle_read(self): asynchat.async_chat.handle_read(self)
def handle_write(self): asynchat.async_chat.handle_write(self)
def readable(self): return asynchat.async_chat.readable(self)
def writable(self): return asynchat.async_chat.writable(self)
Abdullah Yoldas
On 3/15/06, Z. Kotzer [EMAIL PROTECTED] wrote:
I can not get error notifications when an asynchat based client tries toconnect to a non-responsive address.
To validate the problem I changed lib/test/test_asynchat.py as follows:class echo_client(asynchat.async_chat): def __init__(self): asynchat.async_chat.__init__(self) self.create_socket
(socket.AF_INET, socket.SOCK_STREAM) self.connect(('10.135.0.2', PORT)) # Instead of HOST - setan address that does not listen to this port
self.set_terminator(\n) self.buffer = # And added an error handler def handle_error(self): print 'ERROR'
Running it prints nothing - handle_error is not called and nothing is raisedfrom asyncore.loop().Debugging it shows that asyncore.connect gets EWOULDBLOCK and returnsnormally (as may be expected), select in
asyncore.poll returns nothing(including empty e) and the socket remains forever.Anybody has an experience with this behaviour?Thanks in advance!--
http://mail.python.org/mailman/listinfo/python-list
--
http://mail.python.org/mailman/listinfo/python-list