2008-12-25 13 views
9

Próbuję zaimplementować gniazda z timeout recv 1 sekundę:Gniazdo z funkcją time-rec-timeout: Co jest nie tak z tym kodem?

int sockfd; 
struct sockaddr_in self; 
struct sockaddr_in client_addr; 
int addrlen=sizeof(client_addr); 
ssize_t nBytes; 

sockfd = socket(AF_INET, SOCK_STREAM, 0); 

self.sin_family = AF_INET; 
self.sin_port = htons(PORT); 
self.sin_addr.s_addr = INADDR_ANY; 

int on = 1; 
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on); 

// 1 Sec Timeout 
tv.tv_sec = 1; 
tv.tv_usec = 0; 
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv); 

bind(sockfd, (struct sockaddr*)&self, sizeof(self)); 

listen(sockfd, 20); 

clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &addrlen); 

nBytes = recv(clientfd, buffer, MAXBUF-1, 0); 

Bez 'setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, & tv, sizeof (TV);' połączeń, aby zaakceptować i recv praca, ale RECV bloki

z 'setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, & tv, sizeof (TV), zwanej dalej' wezwanie do akceptują produkuje błędzie 'Zasoby chwilowo niedostępny'

Może ktoś proszę powiedzieć. mi co jest nie tak z tym podejściem?

+0

Czy próbowałeś przesuwając setsockopt() zadzwonić do po accept()? – paxdiablo

+0

czy opcje ustawione na gnieździe nasłuchowym (sockfd) mają zastosowanie do gniazd utworzonych przez accept (clientfd)? – Cogsy

Odpowiedz

0

Spróbuj użyć select() przed wywołaniem recv() lub accept().

select() przyjmuje tablicę deskryptorów plików (włącznie z gniazdami) i zwraca, gdy przynajmniej jeden z nich jest gotowy do odbioru. Może również wrócić po przekroczeniu limitu czasu.

W Linuksie możesz również wypróbować poll() (nie jesteś pewien, czy Winsock to zapewnia).

+0

Nie, nie ma. –

4

Oto urywek z użyciem select:

FD_ZERO(&masterfds); 
FD_SET(sockfd,&masterfds); 
memcpy(&readfds,&masterfds,sizeof(fd_set)); 
timeout.tv_sec = 2; 
timeout.tv_usec = 0; 
if (select(sockfd+1, &readfds, NULL, NULL, &timeout) < 0) 
{ 
    printf("select error"); 
    exit(1); 
} 

if (FD_ISSET(sockfd, &readfds)) 
{ 
    //printf("Read from socket\n"); 
    // read from the socket 
    res = recvfrom(sockfd, (char *)hdrbuf, sizeof(hdrbuf), MSG_PEEK, recvaddr, address_len); 
} 
else 
{ 
    // the socket timedout 
    //printf("Socket timeout started=%d\n",packets_started); 
6

Które gniazdo chcesz mieć czas oczekiwania na jedną drugą? Ten, który akceptuje połączenia, lub ten ustalony przez accept()?

Założę, że to drugie - więc spróbuj ustawić limit czasu odbioru na clientfd PO zaakceptowaniu zwraca. Możesz także dostać się tam, gdzie chcesz użyć opcji select, ale nie powinieneś tego robić.

+0

Miałem również wymóg dotyczący limitu czasu. a twoje rozwiązanie pomogło +1. Użyj limitu czasu na nowym deskryptorze połączenia. – RootPhoenix

1

Nic nie jest nie tak ... Kod błędu EAGAIN (Zasób tymczasowo niedostępny) jest dokładnie tym, co powinieneś uzyskać po upływie czasu oczekiwania!

1

Potrzebujesz jeszcze jednego nawiasu zamykającego w każdej z tych dwóch linii.

- setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on); 
+ setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 
- setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv); 
+ setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); 
5

To trochę nie na temat, ale naprawdę chcę udostępnić to rozwiązanie, aby ustawić limit czasu recv zarówno w systemie Windows, jak i w systemie UNIX. Może to ja, ale zajęło mi dużo czasu, aby dowiedzieć się, dlaczego mój program nie działa i jak poprawnie ustawić limit czasu. Mam nadzieję, że okaże się to przydatne. Ustawia limit czasu na 10 sekund.

W systemie Windows:

DWORD sock_timeout = 10*1000; 

dla systemu UNIX:

const struct timeval sock_timeout={.tv_sec=10, .tv_usec=0}; 

Dla obu:

setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&sock_timeout, sizeof(sock_timeout)); 
Powiązane problemy