2011-06-13 42 views
12

Tengo un problema al llamar a la llamada al sistema recv() no se bloquea. Tengo una configuración de estructura cliente-servidor en el momento, y el problema que estoy teniendo es que envío al servidor un mensaje, mientras que el servidor está configurado para que sea algo como:Sockets C/C++ y un recv no de bloqueo()

while (1) { 
    char buf[1024]; 
    recv(fd, buf, sizeof(buf), flags); 
    processMsg(buf); 
} 

Se recibe el primer mensaje correctamente, pero el recv() no bloquea y "recibe" datos de basura que no son los deseados. Me gustaría reaccionar a los mensajes solo cuando se envían. ¿Alguien puede aconsejar?

+12

Es mejor que compruebe el código de retorno de 'recv'. Puede gritar sobre un error mientras está mirando felizmente algo de basura en su búfer ... –

+1

También debe pensar en la posibilidad de recibir parte de un mensaje o más bytes que el valor de un mensaje. Si el emisor transmite mensajes de 500 bytes, su llamada RECV solo podría recuperar 200 bytes o podría recuperar 700 bytes (si su remitente puede transmitir más de un mensaje sin esperar una respuesta). –

+0

Debería haber incluido un enlace a [esta discusión sobre Fragmentación TCP] (http://stackoverflow.com/questions/4552855/tcp-fragmentation) en mi comentario anterior. –

Respuesta

11

recv() no necesariamente se bloqueará hasta que la solicitud completa se ha cumplido, pero puede devolver una petición parcial. El código de retorno le informará cuántos bytes se recibieron realmente, que pueden ser menores a los solicitados. Incluso si especifica un indicador MSG_WAITALL, puede devolver menos debido a una señal, etc.

En los sistemas posix, en el modo de bloqueo, recv solo bloqueará hasta que haya algunos datos para leer. A continuación, devolverá esa información, que puede ser inferior a la solicitada, hasta la cantidad solicitada. En modo no bloqueante, recv volverá inmediatamente si hay cero bytes de datos para leer y devolverá -1, configurando errno en EAGAIN o EWOULDBLOCK.

El resultado es que normalmente llamará a recv en un bucle hasta obtener la cantidad que desea mientras también verifica los códigos de retorno de 0 (otro lado desconectado) o -1 (algún error).

No puedo hablar sobre el comportamiento de Windows.

12

Hay dos posibilidades: o bien se está produciendo un error, o el socket está configurado en modo no bloqueante. Para ver si se produce un error, compruebe el valor de retorno de recv:

while() { 
    char buf[1024]; 
    int ret = recv(,buf,,) 

    if(ret < 0) { 
     // handle error 
     printf("recv error: %s\n", strerror(errno)); 
    } else { 
     // only use the first ret bytes of buf 
     processMsg(buf, ret); 
    } 
} 

a colocar el conector en el modo de no bloqueo, o para saber si un enchufe está en modo de no bloqueo, utilice fcntl(2) con el O_NONBLOCK bandera:

// Test if the socket is in non-blocking mode: 
if(fcntl(sockfd, F_GETFL) & O_NONBLOCK) { 
    // socket is non-blocking 
} 

// Put the socket in non-blocking mode: 
if(fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK) < 0) { 
    // handle error 
} 

Tenga en cuenta que a menos que esté cambiando de forma explícita el comportamiento de bloqueo, la toma debe estar bloqueando de forma predeterminada, lo que muy probablemente se está produciendo un error.

+3

Hay un error tipográfico en la segunda declaración if (sockfg => sockfd) – MonoThreaded

+3

Esto es más útil que la respuesta aceptada ... – Wolfer

Cuestiones relacionadas