Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I determine if a non-blocking socket is really connected?

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()
like image 589
HelloWorld Avatar asked Dec 09 '13 17:12

HelloWorld


People also ask

How do I know if my socket is connected?

How do you check socket is connected or not? If you need to determine the current state of the connection, make a nonblocking, zero-byte Send call. If the call returns successfully or throws a WAEWOULDBLOCK error code (10035), then the socket is still connected; otherwise, the socket is no longer connected.

How do you know if a socket is blocked?

On a blocking socket, the return value indicates success or failure of the connection attempt. With a nonblocking socket, the connection attempt cannot be completed immediately. In this case, connect will return SOCKET_ERROR , and WSAGetLastError() will return WSAEWOULDBLOCK.

How do you set a non-blocking socket?

To mark a socket as non-blocking, we use the fcntl system call. Here's an example: int flags = guard(fcntl(socket_fd, F_GETFL), "could not get file flags"); guard(fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK), "could not set file flags"); Here's a complete example.

How does a non-blocking socket work?

If the blocking mode is set for a socket, the calling program is suspended until the expected event completes. If nonblocking is set by the FCNTL() or IOCTL() calls, the calling program continues even though the I/O call might not have completed.


1 Answers

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.
like image 86
mpontillo Avatar answered Sep 18 '22 13:09

mpontillo