Мне нужно установить тайм-аут для метода recv сокета python. Как это сделать?
Мне нужно установить тайм-аут для метода recv сокета python. Как это сделать?
Ответы:
Типичный подход - использовать 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()
, но я вижу, что вы явно отклонили это решение в другом ответе.
select
- это хорошо, но та часть, где вы говорите «вы не можете», вводит в заблуждение, поскольку есть socket.settimeout()
.
select
- если вы работаете на машине с Windows, select
полагается на библиотеку WinSock, которая имеет привычку возвращаться, как только будут получены некоторые данные, но не обязательно все . Таким образом, вам нужно включить цикл, чтобы продолжать звонить, select.select()
пока не будут получены все данные. Как вы узнаете, что получили все данные (к сожалению), решать вам - это может означать поиск строки терминатора, определенное количество байтов или просто ожидание определенного тайм-аута.
ready[0]
бы неверно, только если бы в ответе сервера нет тела?
есть socket.settimeout()
select
является предпочтительным, когда это решение является однострочным (проще в обслуживании, меньше рисков при неправильной реализации) и использует select под капотом (реализация такая же, как и ответ @DanielStuzbach).
Как уже упоминалось, 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)
.settimeout()
более одного раза, вы можете setdefaulttimeout()
в первую очередь вызвать метод.
Тайм-аут, который вы ищете, - это тайм-аут сокета подключения, а не основного сокета, если вы реализуете серверную часть. Другими словами, существует еще один тайм-аут для объекта сокета подключения, который является выходом 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)
Как упоминалось в предыдущих ответах, вы можете использовать что-то вроде: .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()
Надеюсь, это поможет!!
Вы можете использовать socket.settimeout()
which принимает целочисленный аргумент, представляющий количество секунд. Например, socket.settimeout(1)
установит тайм-аут на 1 секунду.
попробуйте это, он использует базовый C.
timeval = struct.pack('ll', 2, 100)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
SO_RCVTIMEO
и SO_SNDTIMEO
.
2
и почему 100
? Какое значение тайм-аута? В каком агрегате?
timeval = struct.pack('ll', sec, usec)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
usec = 10000 означает 10 мс
#! /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
Кричать, чтобы: https://boltons.readthedocs.io/en/latest/socketutils.html
Он предоставляет буферизованный сокет, который предоставляет множество очень полезных функций, таких как:
.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)