2009-05-14 25 views
10

Aquí hay una versión simplificada de un cierto código que estoy trabajando:Si un recv no bloqueante con MSG_PEEK tiene éxito, ¿tendrá éxito un recv posterior sin MSG_PEEK?

void 
stuff(int fd) 
{ 
    int ret1, ret2; 
    char buffer[32]; 

    ret1 = recv(fd, buffer, 32, MSG_PEEK | MSG_DONTWAIT); 

    /* Error handling -- and EAGAIN handling -- would go here. Bail if 
     necessary. Otherwise, keep going. */ 

    /* Can this call to recv fail, setting errno to EAGAIN? */ 
    ret2 = recv(fd, buffer, ret1, 0); 
} 

Si suponemos que la primera llamada a recv tiene éxito, devuelve un valor entre 1 y 32, es seguro asumir que la segunda llamada también tendrá éxito? ¿Puede ret2 ser menor que ret1? En que casos?

(Para mayor claridad, suponga que no hay otras condiciones de error durante la segunda llamada a recv: que no se envía ninguna señal, que no configurará ENOMEM, etc. También suponga que no se verán otros subprocesos en fd .

estoy en Linux, pero MSG_DONTWAIT es, creo, la única cosa específica de Linux aquí. Supongamos que el fnctl derecho se haya establecido previamente en otras plataformas.)

Respuesta

1

no estoy seguro acerca de EAGAIN , pero piense que EBADF o ECONNRESET son posibles.

+0

'EBADF' no es posible a menos que otro hilo cierre' fd' entre las dos llamadas a 'recv'. – pts

7

El estándar POSIX especifica que con MSG_PEEK, "los datos se tratan como no leídos y la próxima función recv() o similar aún devolverá estos datos". Eso parece significar que a menos que ret2 sea -1, será lo mismo que ret1.

5

También debe considerar la posibilidad de que se pueda llamar a una llamada diferente, en un hilo diferente, entre ret1 y ret2. Esa otra llamada obtendría tus datos, dejando ret2 para terminar sin datos o inesperadamente menos datos.

Si su aplicación no tiene múltiples subprocesos o está diseñada para que fd solo la utilicen estas dos llamadas, puede ignorarla. Pero si esto es un riesgo, entonces debe colocar las dos llamadas dentro de un mecanismo de bloqueo.

+3

Alguien más puede tomar los datos entre estas dos llamadas a 'recv' es posible incluso con programas de subproceso único: otro proceso con el mismo descriptor de archivo de socket abierto podría captar los datos. Un manejador de señal en el mismo proceso también podría tomar los datos. (Afortunadamente, los controladores de señal en su código son generalmente fáciles de controlar). – pts

0

Para su caso simple, la siguiente recv devolverá el número de bytes ret1 (si ret1 no fue un error). Sin embargo, para el diseño de subprocesos múltiples, puede no ser siempre cierto.

2

Su segunda llamada a recv() sin MSG_PEEK puede fallar con EINTR o devolver datos incompletos porque ha sido interrumpida por una señal.

Cuestiones relacionadas