Muszę ustawić limit czasu w metodzie recv gniazda Pythona. Jak to zrobić?
Muszę ustawić limit czasu w metodzie recv gniazda Pythona. Jak to zrobić?
Odpowiedzi:
Typowym podejściem jest użycie funkcji select () do czekania, aż dane będą dostępne lub do upływu limitu czasu. Dzwoń tylko recv()
wtedy, gdy dane są rzeczywiście dostępne. Aby być bezpiecznym, ustawiliśmy również gniazdo w trybie nieblokującym, aby zagwarantować, że recv()
nigdy nie będzie blokować się w nieskończoność. select()
może również służyć do oczekiwania na więcej niż jednym gnieździe naraz.
import select
mysocket.setblocking(0)
ready = select.select([mysocket], [], [], timeout_in_seconds)
if ready[0]:
data = mysocket.recv(4096)
Jeśli masz dużo otwartych deskryptorów plików, poll () jest bardziej wydajną alternatywą dla select()
.
Inną opcją jest ustawienie limitu czasu dla wszystkich operacji na gnieździe przy użyciu socket.settimeout()
, ale widzę, że jawnie odrzuciłeś to rozwiązanie w innej odpowiedzi.
select
jest dobre, ale część, w której mówisz „nie możesz”, jest myląca, ponieważ tak jest socket.settimeout()
.
select
- jeśli pracujesz na komputerze z systemem Windows, select
polega na bibliotece WinSock, która ma zwyczaj zwracania danych, gdy tylko nadejdą niektóre dane, ale niekoniecznie wszystkie . Musisz więc włączyć pętlę, aby dzwonić select.select()
do momentu odebrania wszystkich danych. Skąd wiesz, że uzyskałeś wszystkie dane, zależy (niestety) od Ciebie - może to oznaczać szukanie łańcucha terminatora, określonej liczby bajtów lub po prostu czekanie na określony limit czasu.
ready[0]
byłaby fałszywa tylko wtedy, gdyby w odpowiedzi serwera nie było treści?
jest socket.settimeout()
select
preferowane jest rozwiązanie, które wykorzystuje, gdy jest to rozwiązanie one liner (łatwiejsze w utrzymaniu, mniejsze ryzyko błędnego wdrożenia) i używa select pod maską (implementacja jest taka sama jak odpowiedź @DanielStuzbach).
Jak wspomniano, oba select.select()
i socket.settimeout()
będą działać.
Pamiętaj, że możesz potrzebować zadzwonić settimeout
dwa razy, np
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()
więcej niż raz, możesz najpierw wywołać setdefaulttimeout()
metodę.
Limit czasu, którego szukasz, to limit czasu gniazda połączeniowego, a nie gniazda podstawowego, jeśli implementujesz po stronie serwera. Innymi słowy, istnieje inny limit czasu dla obiektu gniazda połączeniowego, który jest wyjściem socket.accept()
metody method. W związku z tym:
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.
Jeśli wdrożysz stronę klienta, byłoby to proste.
sock.connect(server_address)
sock.settimeout(3)
Jak wspomniano w poprzednich odpowiedziach, możesz użyć czegoś takiego: .settimeout()
Na przykład:
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()
Mam nadzieję, że to pomoże!!
Możesz użyć, socket.settimeout()
który akceptuje argument będący liczbą całkowitą reprezentującą liczbę sekund. Na przykład socket.settimeout(1)
ustawi limit czasu na 1 sekundę
spróbuj tego, używa podstawowego C.
timeval = struct.pack('ll', 2, 100)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
SO_RCVTIMEO
i SO_SNDTIMEO
.
2
i dlaczego 100
? Jaka jest wartość limitu czasu? W jakiej jednostce?
timeval = struct.pack('ll', sec, usec)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
usec = 10000 oznacza 10 ms
#! /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
Krzycz do: https://boltons.readthedocs.io/en/latest/socketutils.html
Zapewnia buforowane gniazdo, co zapewnia wiele bardzo przydatnych funkcji, takich jak:
.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)