2010-01-05 9 views
5

Estoy portando una aplicación de red de Windows a Linux y tuve que enfrentar un problema de tiempo de espera con Select Call en Linux. La siguiente función bloquea el valor de tiempo de espera completo y regresa mientras comprobé con un sniffer de paquete que el cliente ya ha enviado los datos.Socket select() funciona en Windows y agota el tiempo de espera en Linux

int recvTimeOutTCP(SOCKET socket, long sec, long usec) 
{ 
    struct timeval timeout; 
    fd_set fds;. 

    timeout.tv_sec = sec; 
    timeout.tv_usec = usec; 
    FD_ZERO(&fds); 
    FD_SET(socket, &fds); 

    // Possible return values: 
    // -1: error occurred 
    // 0: timed out 
    // > 0: data ready to be read 
    cerr << "Waiting on fd " << socket << endl; 
    return select(1, &fds, 0, 0, &timeout); 
} 

Respuesta

12

creo que el primer parámetro a select() debe ser socket+1.

Deberías usar otro nombre como socket también se usa para otras cosas. Usualmente se usa sock.

+0

@jamessan Ah, sí, quise decir eso;) – epatel

+0

Sí, gracias, eso resolvió mi problema. –

+0

Derecha. 'int select (int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval * timeout);' donde nfds es 'el descriptor de archivo de mayor numeración en cualquiera de los tres conjuntos, más 1'. – jamessan

2

Desde la página del manual de select:

int select(int nfds, 
      fd_set* restrict readfds, 
      fd_set* restrict writefds, 
      fd_set* restrict errorfds, 
      struct timeval* restrict timeout); 

Los primeros nfds descriptores se comprueban en cada juego; es decir, se examinan los descriptores de 0 a nfds-1 en los conjuntos de descriptores.

Así, el primer parámetro para seleccionar debe ser socket + 1.

return select(socket + 1, &fds, 0, 0, &timeout); 
1

El primer parámetro a select (...) es el número de descriptor de archivo para comprobar en el conjunto. Su llamada le dice que solo observe el descriptor de archivo 0, que es casi seguro que no está configurado en socket.

2

select en Windows ignora el primer parámetro. De MSDN:

C++ 
int select(
    __in  int nfds, 
    __inout fd_set *readfds, 
    __inout fd_set *writefds, 
    __inout fd_set *exceptfds, 
    __in  const struct timeval *timeout 
); 

Parameters 

nfds [in] 

    Ignored. The nfds parameter is included only for 
    compatibility with Berkeley sockets. 
...
2

La cuestión es que el fd_set en Linux es una matriz de bits (originalmente era sólo un int, pero entonces sólo se podía ver a los primeros 16 io de de su proceso). En Windows, fd_set es una matriz de sockets con una longitud en la parte frontal (por lo que Windows no necesita saber cuántos bits ver).

La función poll() toma una matriz de registros para ver en Linux y tiene otros beneficios que la convierten en una mejor opción que select().

int recvTimeOutTCP(SOCKET socket, long msec) 
{ 
    int iret ; 
    struct polldf sockpoll ; 

    sockpoll.fd= socket ; 
    sockpoll.events= POLLIN ; 

    return poll(& sockpoll, 1, msec) ; 
} 
+0

Gracias por la información, ¿es esta plataforma cruzada de la función poll() por casualidad? –

+0

Hmm, en Linux realmente quieres usar epoll, preferiblemente en modo de disparo por flanco. –

Cuestiones relacionadas