2010-05-31 68 views
7

Quiero utilizar recv syscall con flags nonblocking MSG_NONBLOCK. Pero con este indicador, syscall puede regresar antes de que se satisfaga la solicitud completa. Entonces,recv con MSG_NONBLOCK y MSG_WAITALL

  • puedo agregar el indicador MSG_WAITALL? ¿Será no bloqueante?
  • o cómo debería reescribir el bloqueo de recv en el bucle con recv sin bloqueo
+0

Supongo que quiere ahorrar memoria de proceso de usuario (para almacenar en búfer el mensaje incompleto), por lo que desea utilizar kernel-memory. Dudo que funcione. –

Respuesta

3

EDIT:

recv normal() devolverá lo que haya en el búfer TCP en el momento de la llamada a la solicitada número de bytes. MSG_DONTWAIT solo evita el bloqueo si no hay datos listos para leer en el socket. MSG_WAITALL solicita el bloqueo hasta que se pueda leer el número completo de bytes solicitados. Entonces no obtendrás un comportamiento de "todo o nada". En el mejor de los casos, debería obtener EAGAIN si no hay datos presentes y bloquear hasta que el mensaje completo esté disponible en caso contrario.

Es posible que pueda crear algo a partir de MSG_PEEK o ioctl() con un FIONREAD (si su sistema lo admite) que se comporta de manera efectiva como usted lo desea, pero no sé cómo puede lograr su objetivo simplemente utilizando el recv() banderas.

+1

NONBLOCK puede regresar con solo una parte del mensaje requerido. Quiero obtener EAGAIN de forma no bloqueante recv, si desea devolver solo una parte de msg. Por lo tanto, quiero recv sin bloqueo con comportamiento "todo o nada" – osgx

4

Esto es lo que hice por el mismo problema, pero me gustaría alguna confirmación de que esto funciona como se esperaba ...

ssize_t recv_allOrNothing(int socket_id, void *buffer, size_t buffer_len, bool block = false) 
{ 
    if(!block) 
    { 
     ssize_t bytes_received = recv(socket_id, buffer, buffer_len, MSG_DONTWAIT | MSG_PEEK); 

     if (bytes_received == -1) 
      return -1; 

     if ((size_t)bytes_received != buffer_len) 
      return 0; 
    } 

    return recv(socket_id, buffer, buffer_len, MSG_WAITALL); 
} 
2

Para IPv4 TCP recibe en Linux, al menos, MSG_WAITALL se ignora si MSG_NONBLOCK está especificado (o el descriptor de archivo está configurado como no bloqueante).

De tcp_recvmsg() en net/ipv4/tcp.c en el núcleo de Linux:

if (copied >= target && !sk->sk_backlog.tail) 
     break; 

if (copied) { 
     if (sk->sk_err || 
      sk->sk_state == TCP_CLOSE || 
      (sk->sk_shutdown & RCV_SHUTDOWN) || 
      !timeo || 
      signal_pending(current)) 
       break; 

objetivo en este reparto se establece en al tamaño solicitado si no se especifica MSG_DONTWAIT o algún valor menor (al menos 1) si no. La función completará si:

  1. bytes suficientes han sido copiados
  2. Hay un error de socket
  3. El conector se haya cerrado o apagado
  4. Timeo se encuentra a 0 (socket se establece en no-bloqueo)
  5. Hay una señal pendiente para el proceso

para mí esto parece que puede ser un error en Linux, pero de cualquier manera no va a funcionar de la manera deseada. Parece que la solución de dec-vt100 lo hará, pero existe una condición de carrera si intentas recibir desde el mismo socket en más de un proceso o subproceso.
Es decir, otra llamada recv() por otro subproceso/proceso podría ocurrir después de que su subproceso ha realizado un vistazo, haciendo que su subproceso se bloquee en el segundo recv().

Cuestiones relacionadas