2008-12-25 15 views
9

estoy tratando de poner en práctica una toma de corriente con un tiempo de espera de 1 segundo recv:Toma con recv-timeout: ¿Qué hay de malo con este código?

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); 

Sin 'setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, & televisión, sizeof (tv);' las llamadas a aceptar y recv . trabajo, pero recv bloques

con 'setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, & televisión, sizeof (tv);' la llamada a aceptar produce el error 'Recurso disponible temporalmente'

puede alguien decir. ¿Qué pasa con este enfoque?

+0

¿Ha intentado mover el setsockopt() para después de la accept()? – paxdiablo

+0

¿las opciones configuradas en el socket de escucha (sockfd) se aplican a los sockets creados por accept (clientfd)? – Cogsy

Respuesta

0

Pruebe usar select() antes de llamar a recv() o accept().

select() toma una matriz de descriptores de archivos (incluidos los sockets) y los devuelve cuando al menos uno de ellos está listo para recibir. También puede regresar en un tiempo de espera.

En Linux también puede probar poll() (no estoy seguro si Winsock proporciona esto).

+0

No, no es así. –

4

He aquí un fragmento usando 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

Qué haces zócalo que desea tener un segundo tiempo de espera en? ¿El que acepta conexiones, o el establecido por accept()?

Supongo que esto último, así que intente configurar el tiempo de espera de recepción en clientfd DESPUÉS de que el accept regrese. También puede llegar a donde necesita usar seleccionar, pero no debería necesitarlo.

+0

Tuve un requisito de tiempo de espera también. y tu solución ayudó a +1. Use tiempo de espera en el nuevo descriptor de conexión. – RootPhoenix

1

No hay nada mal ... ¡El código de error EAGAIN (Recurso temporalmente no disponible) es exactamente lo que debería obtener después de que expire el tiempo de espera!

1

Necesita un paréntesis de cierre más en cada una de estas dos líneas.

- 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

Esto es poco fuera de tema, pero realmente quiero compartir esta solución para establecer el tiempo de espera recv tanto en Windows y UNIX. Tal vez soy yo, pero me llevó mucho tiempo descubrir por qué mi programa no funciona y cómo configurar el tiempo de espera correctamente. Esperamos que te sea útil. Establece el tiempo de espera en 10 segundos.

Para Windows:

DWORD sock_timeout = 10*1000; 

para UNIX:

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

Por tanto:

setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&sock_timeout, sizeof(sock_timeout)); 
Cuestiones relacionadas