Linux: czy istnieje odczyt lub odzyskanie z gniazda z przekroczeniem limitu czasu?
106
Jak mogę spróbować odczytać dane z gniazda z przekroczeniem limitu czasu? Wiem, select, pselect, poll, ma pole limitu czasu, ale ich użycie wyłącza "tcp fast-path" w stosie tcp reno.
Jedyny pomysł, jaki mam, to użycie recv (fd, ..., MSG_DONTWAIT) w pętli
Możesz użyć funkcji setsockopt, aby ustawić limit czasu dla operacji odbierania:
SO_RCVTIMEO
Ustawia wartość limitu czasu, która określa maksymalny czas, przez jaki funkcja wejściowa oczekuje do zakończenia. Akceptuje strukturę czasu z liczbą sekund i mikrosekund określającą limit czasu oczekiwania na zakończenie operacji wejściowej. Jeśli operacja odbioru została zablokowana przez tak długi czas bez otrzymywania dodatkowych danych, powinna powrócić z częściowym zliczaniem lub errno ustawionym na [EAGAIN] lub [EWOULDBLOCK], jeśli żadne dane nie są odbierane. Wartością domyślną dla tej opcji jest zero, co oznacza, że operacja odbierania nie powinna przekraczać limitu czasu. Ta opcja ma strukturę chronologiczną. Zauważ, że nie wszystkie implementacje pozwalają na ustawienie tej opcji.
// LINUXstruct timeval tv;
tv.tv_sec = timeout_in_seconds;
tv.tv_usec =0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO,(constchar*)&tv,sizeof tv);// WINDOWS
DWORD timeout = timeout_in_seconds *1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO,(constchar*)&timeout,sizeof timeout);// MAC OS X (identical to Linux)struct timeval tv;
tv.tv_sec = timeout_in_seconds;
tv.tv_usec =0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO,(constchar*)&tv,sizeof tv);
Podobno w systemie Windows należy to zrobić przed wywołaniem bind. Eksperymentalnie potwierdziłem, że można to zrobić przed lub po bindw systemie Linux i OS X.
Właśnie dlatego limit czasu w systemie Windows nie działa, ponieważ używam kodu dla systemu Linux. Dzięki. Jeśli system Windows nie jest używany, struct timeval tv;czy oznacza to, że funkcja select () też nie będzie działać? Próbowałem przenieść mój kod select () do systemu Windows i natychmiast przekroczył limit czasu, wygląda na to, że ignoruje wartość, którą ustawiam w timeval.
Oto prosty kod dodający limit czasu do recvfunkcji pollw języku C:
struct pollfd fd;int ret;
fd.fd = mySocket;// your socket handler
fd.events = POLLIN;
ret = poll(&fd,1,1000);// 1 second for timeoutswitch(ret){case-1:// Errorbreak;case0:// Timeout break;default:
recv(mySocket,buf,sizeof(buf),0);// get your databreak;}
nie działałoby to dokładnie tak, jak oczekiwano. pollbędzie czekał na odebranie co najmniej jednego bajtu lub przekroczenia limitu czasu, podczas gdy podczas wywoływania recvfunkcji będzie czekał na sizeof(buf)bajty, powodując jej ponowne zablokowanie, jeśli ten licznik jeszcze nie nadszedł, ale tym razem bez przekroczenia limitu czasu.
Zainstaluj moduł obsługi dla SIGALRM, a następnie użyj alarm()lub ualarm()przed zwykłym blokowaniem recv(). Jeśli alarm się recv()włączy, zwróci błąd z errnoustawieniem na EINTR.
alarmy (i sygnały) to niewłaściwa droga do tego zadania. Jeśli chcę używać szybkiej ścieżki TCP, potrzebuję minimalnego opóźnienia. Sygnały są powolne.
Używamy plików cookie i innych technologii śledzenia w celu poprawy komfortu przeglądania naszej witryny, aby wyświetlać spersonalizowane treści i ukierunkowane reklamy, analizować ruch w naszej witrynie, i zrozumieć, skąd pochodzą nasi goście.
Kontynuując, wyrażasz zgodę na korzystanie z plików cookie i innych technologii śledzenia oraz potwierdzasz, że masz co najmniej 16 lat lub zgodę rodzica lub opiekuna.