Мені потрібно встановити тайм-аут для методу recv socket python. Як це зробити?
Мені потрібно встановити тайм-аут для методу recv socket python. Як це зробити?
Відповіді:
Типовий підхід полягає у використанні select (), щоб чекати, поки дані стануть доступними або до настання тайм-ауту. Телефонуйте лише recv()
тоді, коли дані фактично доступні. В цілях безпеки ми також встановлюємо сокет в незаблокувальний режим, щоб гарантувати, що recv()
він ніколи не блокується безстроково. select()
може також використовуватися для очікування на більш ніж одній розетці одночасно.
import select
mysocket.setblocking(0)
ready = select.select([mysocket], [], [], timeout_in_seconds)
if ready[0]:
data = mysocket.recv(4096)
Якщо у вас є багато відкритих дескрипторів файлів, опитування () є більш ефективною альтернативою select()
.
Інший варіант - встановити тайм-аут для всіх операцій на сокеті, використовуючи socket.settimeout()
, але я бачу, що ви явно відхилили це рішення в іншій відповіді.
select
добре, але частина, де ви говорите "не можете", вводить в оману, оскільки є socket.settimeout()
.
select
- якщо ви працюєте на машині Windows, select
покладається на бібліотеку WinSock, яка має звичку повертатися, як тільки надходять деякі дані, але не обов'язково всі . Тому вам потрібно включити цикл, щоб продовжувати дзвінки, select.select()
поки всі дані не будуть отримані. Як ви знаєте, що ви отримали всі дані, на жаль, вирішувати - це може означати пошук рядка термінатора, певної кількості байтів або просто очікування певного часу очікування.
ready[0]
помилковим буде лише те, що у відповіді сервера немає тіла?
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()
який приймає цілий аргумент, що представляє кількість секунд. Наприклад, socket.settimeout(1)
встановить час очікування на 1 секунду
спробуйте це, він використовує основний С.
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)