469,280 Members | 1,799 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,280 developers. It's quick & easy.

Non-blocking connect

mp
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()
Jun 27 '08 #1
3 7422
In article
<59**********************************@y22g2000prd. googlegroups.com>,
mp <ma*********@email.comwrote:
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.
Jun 27 '08 #2
mp
Thanks Roy. I was just trying to understand someone else's code, but
in the end it turns out that this was just a bug.

What weirded me out was how injecting a print statement preventing the
error from occurring, but now I get it. Without blocking, the
connection handshake occurs in parallel after the connect_exc method
is called. In my example, my processor reaches the send call before
the connection manages to complete in the background. However, if you
stick in a print statement after the connect_exc call and before the
send call, it delays processing just long enough for the connection to
complete, thus no exception is thrown by the send call.
Jun 27 '08 #3
In article
<10**********************************@a9g2000prl.g ooglegroups.com>,
mp <ma*********@email.comwrote:
Thanks Roy. I was just trying to understand someone else's code, but
in the end it turns out that this was just a bug.

What weirded me out was how injecting a print statement preventing the
error from occurring, but now I get it. Without blocking, the
connection handshake occurs in parallel after the connect_exc method
is called. In my example, my processor reaches the send call before
the connection manages to complete in the background. However, if you
stick in a print statement after the connect_exc call and before the
send call, it delays processing just long enough for the connection to
complete, thus no exception is thrown by the send call.
I don't really understand that last part. There shouldn't be any
background processing going on, unless there's a lot more code than you
showed.

The three-way handshake *can't* happen in the background, because
connect_ex() has no way to know what value to return until the handshake is
completed. Let's say I send a SYN, and 15 seconds later, you send a RST
(indicating that the connection has been refused). The connect_ex() call
has to have waited the 15 seconds for this to happen so it knows to return
an appropriate error code.

I do not understand why sticking a print statement in there should make any
difference.
Jun 27 '08 #4

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

12 posts views Thread by lothar | last post: by
25 posts views Thread by Yves Glodt | last post: by
32 posts views Thread by Adrian Herscu | last post: by
8 posts views Thread by Bern McCarty | last post: by
14 posts views Thread by Patrick Kowalzick | last post: by
399 posts views Thread by =?UTF-8?B?Ik1hcnRpbiB2LiBMw7Z3aXMi?= | last post: by
reply views Thread by zhoujie | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.