Do Twojej wiadomości, jeśli zdecydujesz się użyć limitów czasu ... musisz wiedzieć, jak sobie z tym poradzić. to pytanie SO dotyczy obsługi w przypadku przekroczenia limitu czasu: stackoverflow.com/questions/16745409
Trevor Boyd Smith
Odpowiedzi:
126
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.
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.
użycie selectjest dobre, ale część, w której mówisz „nie możesz”, jest myląca, ponieważ tak jest socket.settimeout().
nosklo
1
Teraz jest lepiej, ale nie widzę, gdzie odpowiedź została „wyraźnie odrzucona”.
nosklo
7
Jedno ostrzeżenie dotyczące używania select- jeśli pracujesz na komputerze z systemem Windows, selectpolega 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.
JDM,
4
Dlaczego konieczne jest ustawienie gniazda na nieblokujące? Nie sądzę, aby miało to znaczenie dla wywołania select (i blokuje się do momentu odczytania deskryptora lub wygaśnięcia limitu czasu w tym przypadku), a recv () nie zostanie zablokowany, jeśli wybór zostanie spełniony. Wypróbowałem to za pomocą recvfrom () i wydaje się, że działa poprawnie bez setblocking (0).
HankB
1
Czy ready[0]byłaby fałszywa tylko wtedy, gdyby w odpowiedzi serwera nie było treści?
Nie przekracza limitu czasu recv (przynajmniej kiedy próbowałem). Przekroczono limit czasu tylko funkcji accept ().
Oren S
9
Wydaje się, że socket.recv () przekroczył limit czasu po ustawieniu funkcji socket.settimeout (), dokładnie tak, jak zamierzano. Czy ja to zmyślam? Czy ktoś inny może to potwierdzić?
Aeonaut
3
@Aeonaut Myślę, że to przez większość czasu przekracza recv (), ale istnieje warunek wyścigu. W socket.recv () Python (2.6) wywołuje wewnętrznie funkcję select / poll z upływem czasu, a zaraz po tym wywoływana jest funkcja recv (). Więc jeśli używasz gniazda blokującego i między tymi dwoma wywołaniami drugi punkt końcowy ulega awarii, możesz zawiesić się na czas nieokreślony na recv (). Jeśli używasz gniazda nieblokującego, Python nie wywołuje funkcji select.select wewnętrznie, więc myślę, że odpowiedź Daniela Stutzbacha jest poprawna.
emil.p.stanchev
4
Właściwie prawdopodobnie źle zrozumiałem, kiedy funkcja select () zwraca, więc zdrap poprzedni komentarz. Przewodnik Beeja mówi, że powyższe jest prawidłowym sposobem na zaimplementowanie limitu czasu na recv: beej.us/guide/bgnet/output/html/singlepage/, więc ufam, że jest autorytatywnym źródłem.
emil.p.stanchev
2
Nie jestem pewien, dlaczego selectpreferowane 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).
Myślę, że dostaje to samo co ja, gdzie bez względu na to, jak szturchasz i naciskasz, ta funkcja się zawiesza. Wypróbowałem teraz 2 lub 4 limity czasu i nadal się zawiesza. settimeout również się zawiesza.
Casey Daniel,
1
Ponieważ wywołujesz .settimeout()więcej niż raz, możesz najpierw wywołać setdefaulttimeout()metodę.
mvarge
12
Możesz ustawić limit czasu przed otrzymaniem odpowiedzi i po otrzymaniu odpowiedzi ustawić go z powrotem na Brak:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5.0)
data = sock.recv(1024)
sock.settimeout(None)
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.
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 bytesexcept socket.timeout:# fail after 1 second of no activityprint("Didn't receive data! [Timeout]")finally:
s.close()
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ę
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)
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ć, żerecv()
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.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.źródło
select
jest dobre, ale część, w której mówisz „nie możesz”, jest myląca, ponieważ tak jestsocket.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()
źródło
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()
isocket.settimeout()
będą działać.Pamiętaj, że możesz potrzebować zadzwonić
settimeout
dwa razy, npźródło
.settimeout()
więcej niż raz, możesz najpierw wywołaćsetdefaulttimeout()
metodę.Możesz ustawić limit czasu przed otrzymaniem odpowiedzi i po otrzymaniu odpowiedzi ustawić go z powrotem na Brak:
źródło
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:Jeśli wdrożysz stronę klienta, byłoby to proste.
źródło
Jak wspomniano w poprzednich odpowiedziach, możesz użyć czegoś takiego:
.settimeout()
Na przykład:Mam nadzieję, że to pomoże!!
źródło
Możesz użyć,
socket.settimeout()
który akceptuje argument będący liczbą całkowitą reprezentującą liczbę sekund. Na przykładsocket.settimeout(1)
ustawi limit czasu na 1 sekundęźródło
spróbuj tego, używa podstawowego C.
źródło
SO_RCVTIMEO
iSO_SNDTIMEO
.2
i dlaczego100
? 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źródło
Krzycz do: https://boltons.readthedocs.io/en/latest/socketutils.html
Zapewnia buforowane gniazdo, co zapewnia wiele bardzo przydatnych funkcji, takich jak:
źródło