8

This question is not limited to Python. Its a general socket question. I have a non-blocking socket and want to connect to a machine which is reachable - on the other side the port does not exist. Why does select(...) succeed anyway? I expected a timeout. sock.send(...) fails with a broken pipe. How can I determine if the socket is really connected after select(...)? Thanks in advance.

import socket, errno, os, time, select

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setblocking(0)
err = sock.connect_ex(('192.168.178.21', 12345))
ready_to_read, ready_to_write, in_error = select.select([], [sock], [], timeout=5)
#ready_to_write is set even 192.168.178.21:12345 does not exist.

sock.setblocking(1)
sock.send('foo') #this fails
sock.close()
finefoot
  • 9,914
  • 7
  • 59
  • 102
HelloWorld
  • 2,392
  • 3
  • 31
  • 68

1 Answers1

8

Try checking the return values. Here's what I get in a similar situation:

>>> import socket, errno, os, time, select
>>> sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> sock.setblocking(0)
>>> err = sock.connect_ex(('10.0.0.1', 12345))
>>> import errno
>>> print errno.errorcode[err]
EINPROGRESS
>>> print sock.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
61
>>> print errno.errorcode[61]
ECONNREFUSED

The select() call is probably returning because there was an exceptional condition on the socket - that is, its connection was refused.

If I do this, the select() returns immediately:

>>> ready_to_read, ready_to_write, in_error = select.select([], [sock], [])

And interestingly enough, the return values match exactly what you passed in (if you had more than one socket, that would likely be different):

>>> print in_error
[]
>>> print ready_to_read
[]
>>> print ready_to_write
[<socket._socketobject object at 0x10ccd0980>]

The designers of select() are expecting you to run select() in a loop, and if a socket returns an error when you attempt the write, remove it from the list when the write fails.

So you have a couple of options, off the top of my head:

  • Wait until you try to read the socket and fail, then take the appropriate action.
  • Use getsockopt() as I did above to check if the socket is OK, or is in an error state, before attempting to do anything with it.
mpontillo
  • 13,559
  • 7
  • 62
  • 90
  • sock.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) did the trick for me. – HelloWorld Dec 09 '13 at 19:57
  • 2
    ok. keep in mind that the socket could be shut down between `getsockopt()` returning and your attempt to read or write to the socket. so you should still attempt to handle errors on send/recv gracefully. – mpontillo Dec 09 '13 at 20:25