问题:如何在python的socket recv方法上设置超时?
我需要在python的socket recv方法上设置超时。怎么做?
I need to set timeout on python’s socket recv method. How to do it?
回答 0
典型的方法是使用select()等待数据可用或超时。仅recv()
在实际可用数据时调用。为了安全起见,我们还将套接字设置为非阻塞模式,以确保recv()
永远不会无限阻塞。 select()
也可以一次在多个插座上等待。
import select
mysocket.setblocking(0)
ready = select.select([mysocket], [], [], timeout_in_seconds)
if ready[0]:
data = mysocket.recv(4096)
如果您有很多打开的文件描述符,则poll()是更有效的替代方法select()
。
另一个选择是使用设置套接字上所有操作的超时socket.settimeout()
,但是我看到您在另一个答案中明确拒绝了该解决方案。
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[0]:
data = mysocket.recv(4096)
If you have a lot of open file descriptors, poll() is a more efficient alternative to select()
.
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.
回答 1
回答 2
如前所述都select.select()
和socket.settimeout()
正常工作。
请注意,您可能需要打settimeout
两次电话,例如
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)
As mentioned both select.select()
and socket.settimeout()
will work.
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)
回答 3
您可以在收到响应之前设置超时,在收到响应之后将其设置回无:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5.0)
data = sock.recv(1024)
sock.settimeout(None)
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)
回答 4
如果要实现服务器端,则要查找的超时是连接套接字的超时,而不是主套接字的超时。换句话说,连接套接字对象还有另一个超时,这是socket.accept()
方法的输出。因此:
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.
如果实现客户端,那将很简单。
sock.connect(server_address)
sock.settimeout(3)
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.
sock.connect(server_address)
sock.settimeout(3)
回答 5
如先前的答复所述,您可以使用类似以下内容的.settimeout()
示例:
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!\r\n")
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()
我希望这有帮助!!
As mentioned in previous replies, you can use something like: .settimeout()
For example:
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!\r\n")
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!!
回答 6
您可以使用socket.settimeout()
接受代表秒数的整数参数。例如,socket.settimeout(1)
将超时设置为1秒
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
回答 7
尝试使用基础C。
timeval = struct.pack('ll', 2, 100)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
try this it uses the underlying C.
timeval = struct.pack('ll', 2, 100)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
回答 8
#! /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
#! /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
回答 9
Shout out to: https://boltons.readthedocs.io/en/latest/socketutils.html
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)