Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get non-blocking socket connect()'s?

I have a quite simple problem here. I need to communicate with a lot of hosts simultaneously, but I do not really need any synchronization because each request is pretty self sufficient.

Because of that, I chose to work with asynchronous sockets, rather than spamming threads. Now I do have a little problem:

The async stuff works like a charm, but when I connect to 100 hosts, and I get 100 timeouts (timeout = 10 secs) then I wait 1000 seconds, just to find out all my connections failed.

Is there any way to also get non blocking socket connects? My socket is already set to nonBlocking, but calls to connect() are still blocking.

Reducing the timeout is not an acceptable solution.

I am doing this in Python, but I guess the programming language doesnt really matter in this case.

Do I really need to use threads?

like image 590
Tom Avatar asked Jul 30 '09 10:07

Tom


People also ask

Is socket connect blocking?

connect() on a TCP socket is a blocking operation unless the socket descriptor is put into non-blocking mode. A successful TCP handshake will be queued to the server application, and can be accept()'ed any time later.

How would I put my socket in non-blocking mode?

A blocking accept() call does not return to your program until a client connects to your socket program. Change a socket to nonblocking mode using the ioctl() call that specifies command FIONBIO and a fullword (four byte) argument with a nonzero binary value.

Is socket listen blocking?

Listen causes a connection-oriented Socket to listen for incoming connection attempts. The backlog parameter specifies the number of incoming connections that can be queued for acceptance. To determine the maximum number of connections you can specify, retrieve the MaxConnections value. Listen does not block.

What is blocking socket and non-blocking socket?

A socket can be in "blocking mode" or "nonblocking mode." The functions of sockets in blocking (or synchronous) mode do not return until they can complete their action. This is called blocking because the socket whose function was called cannot do anything — is blocked — until the call returns.


1 Answers

When using socket.connect with a non-blocking socket, it is somewhat expected to get a BlockingIOError at first. See TCP Connect error 115 Operation in Progress What is the Cause? for an explanation of the cause.

The solution is to either catch and ignore the exception or to use socket.connect_ex instead of socket.connect because that method doesn't raise an exception. Especially note the last sentence from its description in the Python docs:

socket.connect_ex(address)

Like connect(address), but return an error indicator instead of raising an exception for errors returned by the C-level connect() call (other problems, such as “host not found,” can still raise exceptions). The error indicator is 0 if the operation succeeded, otherwise the value of the errno variable. This is useful to support, for example, asynchronous connects.

Source: https://docs.python.org/3/library/socket.html#socket.socket.connect_ex

If you want to keep using socket.connect, you can catch and ignore the responsible EINPROGRESS error:

>>> import socket
>>> 
>>> # bad
>>> s = socket.socket()
>>> s.setblocking(False)
>>> s.connect(("127.0.0.1", 8080))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
BlockingIOError: [Errno 115] Operation now in progress
>>> 
>>> # good
>>> s = socket.socket()
>>> s.setblocking(False)
>>> try:
...     s.connect(("127.0.0.1", 8080))
... except OSError as exc:
...     if exc.errno != 115:  # EINPROGRESS
...         raise
... 
>>> 
like image 189
finefoot Avatar answered Oct 30 '22 08:10

finefoot