2009-09-06 20 views
11

He estado leyendo Beej's Guide to Network Programming para obtener un control sobre las conexiones TCP. En una de las muestras el código de cliente para un cliente sencillo flujo TCP se parece a:Manejo de retorno parcial desde recv() TCP en C

if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) { 
    perror("recv"); 
    exit(1); 
} 

buf[numbytes] = '\0'; 

printf("Client: received '%s'\n", buf); 

close(sockfd); 

He puesto el buffer a ser menor que el número total de bytes que estoy enviando. No estoy muy seguro de cómo puedo obtener los otros bytes. ¿Tengo que pasar por encima de recv() hasta que reciba '\0'?

* Tenga en cuenta que en el lado del servidor también estoy implementando su función sendall(), por lo que en realidad debería estar enviando todo al cliente.

Véase también 6.1. A Simple Stream Server en la guía.

Respuesta

12

Sí, necesitará múltiples llamadas recv(), hasta que tenga todos los datos.

Para saber cuándo es eso, usar el estado de devolución de recv() no sirve, solo le indica cuántos bytes ha recibido, no cuántos bytes hay disponibles, ya que algunos aún están en tránsito.

Es mejor si los datos que recibe de algún modo codifican la longitud de los datos totales. Lea tantos datos hasta que sepa cuál es la longitud, luego lea hasta que haya recibido length de datos. Para hacer eso, varios enfoques son posibles; el más común es crear un búfer lo suficientemente grande como para contener todos los datos una vez que sepa cuál es la longitud.

Otro enfoque es utilizar almacenamientos intermedios de tamaño fijo, y siempre intente recibir min(missing, bufsize), disminuyendo missing después de cada recv().

+5

Otro enfoque es utilizar el byte final, con especial valor (como ETX) si está seguro de que este valor no puede aparecer dentro del mensaje, o iniciar byte (STX) y byte final (ETX). Es más difícil de manejar en el lado del receptor, pero más robusto. Si algo salió mal y algunos datos se perdieron en la transmisión, el flujo de datos se puede sincronizar fácilmente con STX/ETX, pero en el caso del prefijo de longitud todo se dispara – qrdl

9

La primera cosa que hay que aprender cuando se hace TCP/IP de programación: 1 write/send llamada podría tomar varios recv llamadas para recibir, y varios de escritura/envío de llamadas podrían necesitar sólo 1 recv llamada a recibir. Y cualquier cosa en el medio.

Deberá realizar un bucle hasta que tenga todos los datos. El valor de retorno de recv() le indica la cantidad de datos que recibió. Si simplemente desea recibir todos los datos en la conexión TCP, puede realizar un bucle hasta que recv() devuelva 0, siempre que el otro extremo cierre la conexión TCP cuando finalice el envío.

Si está enviando registros/líneas/paquetes/comandos o algo similar, necesita hacer su propio protocolo sobre TCP, que podría ser tan simple como "los comandos están delimitados con \n".

La manera más sencilla de leer/analizar dicho comando sería leer 1 byte a la vez, crear un búfer con los bytes recibidos y verificar un byte \n todo el tiempo. Leer 1 byte es extremadamente ineficiente, por lo que debe leer fragmentos más grandes a la vez.

Desde TCP se corriente orientada y no proporciona grabación/límites del mensaje se convierte en un poco más complejo - que había tienen que recv una pieza de bytes, compruebe en el búfer recibido por un byte \n, si está allí - añada los bytes a los bytes recibidos previamente y envíe ese mensaje. Luego, verifique el resto del búfer después del \n, que podría contener otro mensaje completo o simplemente el comienzo de otro mensaje.

1

Sí, usted tiene que bucle sobre recv() hasta que reciba '\0' o sucede un error (valor negativo de recv) o 0 de recv(). Para la primera opción: solo si este cero es parte de su protocolo (el servidor lo envía). Sin embargo, desde su código parece que el cero es solo para poder usar el contenido del buffer como una cadena de C (en el lado del cliente).

El cheque por un valor de retorno de 0 de recv: esto significa que la conexión se ha cerrado (que podría ser parte de su protocolo que esto sucede.)

+0

Puede recibir bytes con el valor '\ 0'; el problema es cuando el conteo de los bytes devueltos es 0. –

+0

¿Por qué recibiría un '\ 0'? A menos que él envió uno? No hay evidencia en la pregunta sobre eso. – EJP

Cuestiones relacionadas