I need to set timeout on python’s socket recv method. How to do it?
The typical approach is to use select() to wait until data is available or until the timeout occurs. Only call
recv() when data is actually available. To be safe, we also set the socket to non-blocking mode to guarantee that
recv() will never block indefinitely.
select() can also be used to wait on more than one socket at a time.
import select mysocket.setblocking(0) ready = select.select([mysocket], , , timeout_in_seconds) if ready: data = mysocket.recv(4096)
If you have a lot of open file descriptors, poll() is a more efficient alternative to
Another option is to set a timeout for all operations on the socket using
socket.settimeout(), but I see that you’ve explicitly rejected that solution in another answer.
Note you might need to call
settimeout twice for your needs, e.g.
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(("",0)) sock.listen(1) # accept can throw socket.timeout sock.settimeout(5.0) conn, addr = sock.accept() # recv can throw socket.timeout conn.settimeout(5.0) conn.recv(1024)
You could set timeout before receiving the response and after having received the response set it back to None:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(5.0) data = sock.recv(1024) sock.settimeout(None)
The timeout that you are looking for is the connection socket’s timeout not the primary socket’s, if you implement the server side. In other words, there is another timeout for the connection socket object, which is the output of
socket.accept() method. Therefore:
sock.listen(1) connection, client_address = sock.accept() connection.settimeout(5) # This is the one that affects recv() method. connection.gettimeout() # This should result 5 sock.gettimeout() # This outputs None when not set previously, if I remember correctly.
If you implement the client side, it would be simple.
You can use
socket.settimeout() which accepts a integer argument representing number of seconds. For example,
socket.settimeout(1) will set the timeout to 1 second
try this it uses the underlying C.
timeval = struct.pack('ll', 2, 100) s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
As mentioned in previous replies, you can use something like:
import socket s = socket.socket() s.settimeout(1) # Sets the socket to timeout after 1 second of no activity host, port = "somehost", 4444 s.connect((host, port)) s.send("Hello World!rn") try: rec = s.recv(100) # try to receive 100 bytes except socket.timeout: # fail after 1 second of no activity print("Didn't receive data! [Timeout]") finally: s.close()
I hope this helps!!
#! /usr/bin/python3.6 # -*- coding: utf-8 -*- import socket import time s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) s.settimeout(5) PORT = 10801 s.bind(('', PORT)) print('Listening for broadcast at ', s.getsockname()) BUFFER_SIZE = 4096 while True: try: data, address = s.recvfrom(BUFFER_SIZE) except socket.timeout: print("Didn't receive data! [Timeout 5s]") continue
It provides a buffered socket, this provides a lot of very useful functionality such as:
.recv_until() #recv until occurrence of bytes .recv_closed() #recv until close .peek() #peek at buffer but don't pop values .settimeout() #configure timeout (including recv timeout)
Got a bit confused from the top answers so I’ve wrote a small gist with examples for better understanding.
Option #1 –
Will raise an exception in case the
sock.recv() waits for more than the defined timeout.
import socket sock = socket.create_connection(('neverssl.com', 80)) timeout_seconds = 2 sock.settimeout(timeout_seconds) sock.send(b'GET / HTTP/1.1rnHost: neverssl.comrnrn') data = sock.recv(4096) data = sock.recv(4096) # <- will raise a socket.timeout exception here
Option #2 –
Waits until data is sent until the timeout is reached. I’ve tweaked Daniel’s answer so it will raise an exception
import select import socket def recv_timeout(sock, bytes_to_read, timeout_seconds): sock.setblocking(0) ready = select.select([sock], , , timeout_seconds) if ready: return sock.recv(bytes_to_read) raise socket.timeout() sock = socket.create_connection(('neverssl.com', 80)) timeout_seconds = 2 sock.send(b'GET / HTTP/1.1rnHost: neverssl.comrnrn') data = recv_timeout(sock, 4096, timeout_seconds) data = recv_timeout(sock, 4096, timeout_seconds) # <- will raise a socket.timeout exception here