The joys and jilts of non-blocking sockets

Robert Amesz rcameszREMOVETHIS at dds.removethistoo.nl
Mon May 14 13:24:15 EDT 2001


Timothy O'Malley wrote:

> In article <Xns90989FD82A446rcamesz at 127.0.0.1>, Robert Amesz wrote:
>
>> [non-blocking socket fix for TimeOutSocket.py] 
> 
> All true.  In version 1.16, ok?

That's fine with me, thanks.


>> If the host exists and can be reached, connecting to it using a
>> non- blocking call *always* leads to this exception:
>> 
>>    (10035, 'The socket operation could not complete without
>>    blocking') 10035 = EWOULDBLOCK     WSAEWOULDBLOCK
>> 
>> This message does not give you *any* information about the status
>> of the connection: the machine may be busy connecting, the
>> connection may have been made, or the connection may have been
>> refused. 
> 
> You lose me here.  By using a non-blocking socket, you have told
> the operating system that it should never block on this socket.
> In that case, I expect this exception.  The operating system is
> informing you that the operation would block (because it wasn't
> finished) when you made the connect() call.  This is all standard
> and routine behavior for non-blocking sockets.

Perhaps I haven't made myself clear. The point I'm trying to make is
that I'm suprised that an exception is raised for a case which is not
exceptional at all. It's more of an aesthetic argument, but

  try:
      MySock.connect(('some.dot.com', 80))  # Nonblocking socket
      # This point cannot be reached

  except socket.error e:
    	if e[0] != EWOULDBLOCK:
           raise

just seems ugly and obtuse. Oh, I can live with it, but Python doesn't 
usually offend my sensibilities in this way.


>> But don't despair: if a connection is refused trying to connect
>> again to the same host using the same socket will yield the
>> following surprising exception:
>> 
>>    (10022, 'Invalid argument')
>>    10022 =                 WSAEINVAL
> 
> In fact, once the socket is 'writeable' (using the above test), you
> are supposed to call connect() again.  The result of the second
> connect() call determines the result of the overall connection
> operation.
> 
> I admit, I do not know what this Windows error message means.  Even
> so, that does not mean that it is a failure of the interface.
> Sometimes connections have errors -- this is all part of normal
> operation.

I've been looking through the Winsock API doc's and I've found the
reason:

   WSAEALREADY
   A non-blocking connect call is in progress on the specified
   socket.
   Note  In order to preserve backward compatibility, this
   error is reported as WSAEINVAL to Windows Sockets 1.1 applications
   that link to either WINSOCK.DLL or WSOCK32.DLL.

So it would seem that this is an old Winsock-bug, preserved for 
compatibility reasons. This could easily be fixed by either having 
WSAStartup() request Winsock version 2.0, or checking the return code 
from connect() for WSAEINVAL and replacing it with WSAEALREADY.


>> As sockets can't be re-used anyway this isn't something to look
>> into too deeply. After a close() all further operations on that
>> socket are are expressly forbidden, and in fact impossible. Yes, I
>> just had to try! Although the exception you get when you try to
>> reconnect is pretty puzzling: 
>> 
>>    AttributeError: 'int' object has no attribute 'connect'
> 
> Ooops.  That looks like a TimeoutSocket bug.

Don't worry: it's the standard socket module which is to blame. It 
apparrently replaces the internal _socket object with the integer 0 
when closed. 


> In summary of this long message.....
>   - Thanks for the bug report.

You're very welcome.


> - You are right about the non-blocking inadequacies of
>   TimeoutSocket.

Shouldn't be hard to fix, though.


> - Much of what you have complained about is
>   standard procedure when using sockets.

I wasn't complaining, just describing my experiences. But I'm happy you 
confirmed that many things *are* standard procedure, and not just 
winsock things.


> A whirlwind tour through BSD sockets would explain some of the
> history. 

Perhaps I should. The documentation that I have on Berkely sockets 
isn't very extensive and doesn't address non-blocking sockets at all. 
I'm sure the web will yield more comprehensive information, though, if 
I care to look for it.

Besides, there are differences between sockets implementations on 
different platforms, and the Python socket module doesn't do much, it 
would seem, to isolate the Python programmer from those platform 
dependencies. I'm not sure that is a good decision, but I'm afraid 
we'll have to live with it.

Thank you for your comments.


Robert Amesz



More information about the Python-list mailing list