Non-blocking connect

Roy Smith roy at panix.com
Fri May 2 14:03:47 EDT 2008


In article 
<59915ad0-2af1-4903-8ffd-48da2ce4e647 at y22g2000prd.googlegroups.com>,
 mp <mailpitches at email.com> wrote:

> Code is at bottom. Basically, if I turn off socket blocking prior to
> connecting, I get a "Socket is not connected" error when I try to send
> data. However, if I do not turn off blocking, OR if I place a print
> statement anywhere before the send call, it works! WTF?
> 
> I'd like to understand what's going on in the background here, if you
> know don't skimp on the details.
> 
> Thanks
> 
> ---------------------------------------------------------------
> import
> socket
> sock = socket.socket(socket.AF_INET,
> socket.SOCK_STREAM)
> sock.setblocking(0)
> sock.connect_ex(('localhost',
> 9000))
> sock.setblocking(1)
> sock.send('foo')
> sock.close()

I can't be 100% sure about this because I don't know what's running on your 
port 9000 that you're trying to connect to, but I think I know what's going 
on.

I just tried your code, but changed 9000 to 22 (ssh).  What I found is that 
if you eliminate the setblocking(0) call, the connect_ex() call returns 0, 
indicating it succeeded.  If you leave the setblocking(0) call in, 
connect_ex() returns EINPROGRESS (Operation now in progress).  This makes 
sense.  Here's the code:

import socket
import os
import errno

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setblocking(0)
err = sock.connect_ex(('localhost', 22))
print errno.errorcode[err], os.strerror(err)

When you do a TCP connect, there is what's called a three-way handshake 
that happens between the TCP stacks at the two ends of the connection.  I 
send a packet with the SYN bit set, you respond with a packet with both SYN 
and ACK set, and I respond with an ACK.  Even when both ends are on the 
same box (i.e. localhost), this has to happen.

Quoting from http://docs.python.org/lib/socket-objects.html:

> Some notes on socket blocking and timeouts: [...] In non-blocking mode, 
> operations fail (with an error that is unfortunately system-dependent) if 
> they cannot be completed immediately.

Since the three-way handshake can't be completed immediately, the 
connect_ex call fails when you try it in non-blocking mode.

So, that's the explanation.  Now the question: What are you trying to do 
that you need non-blocking mode?  Or are you just experimenting to see what 
happens?

BTW, this was done on an OSX-10.5.2 box, but I think the result would be 
essentially the same on any platform.



More information about the Python-list mailing list