2012-09-29 27 views
9

send() devolverá el número de bytes enviados o el código de error, pero todos los ejemplos que encontré lo comprueban solo con códigos de error, pero no con el número de bytes enviados.¿Send() siempre envía buffer completo?

//typical example 
int cnt=send(s,query,strlen(query),0); 
if (cnt < 0) return(NULL); 
//Hey, what about cnt < strlen(query)? 

Respuesta

13

Q: ¿"send()" siempre devuelve el buffer completo?

A: No, no necesariamente.

De la Guía del Beej: * http://beej.us/guide/bgnet/output/html/multipage/syscalls.html#sendrecv

send() devuelve el número de bytes enviados en realidad fuera de esto podría ser menor que el número que le dijo a enviar! Ver, a veces le dices para enviar una gran cantidad de datos y simplemente no puede manejarlo. Disparará de la mayor cantidad de datos posible y confiará en que envíe el resto más tarde. Recuerde, si el valor devuelto por send() no coincide con el valor en len, le corresponde a usted enviar el resto de la cadena. La buena noticia de es la siguiente: si el paquete es pequeño (menos de 1K o menos) será , probablemente logre enviar todo de una vez. De nuevo, -1 es devuelto por error, y errno se configura con el número de error.

Q: ¿"recv()" siempre lee toda la memoria intermedia?

A: No, absolutamente no. Debe nunca asumir que el buffer que ha recibido es "el mensaje completo". O suponga que el mensaje que recibe es uno, solo mensaje.

Aquí hay una buena y breve explicación. Es para Microsoft/C#, pero es aplicable a todos los tomas de E/S, en cualquier idioma:

+5

-1: Exactamente al revés: para cualquier protocolo basado en flujo (como TCP), el envío puede devolver menos de la cantidad solicitada, si el búfer local ya está casi lleno de envíos anteriores. Para protocolos de datagramas (como UDP), el envío fallará o enviará todo el buffer como un paquete, no es posible enviarlos parcialmente. –

+1

No voté negativamente, pero veo mi respuesta, estás equivocado. –

+0

@Kiril Kirov: usted y Chris Dodd son absolutamente correctos. Fart de mi parte, disculpas. He corregido mi respuesta. ¡Gracias! – paulsm4

3

No, no es así.

Para referencia, ver the man page for send:

Cuando el mensaje no cabe en el buffer de envío del conector, send() normalmente bloquea, a menos que el enchufe se ha colocado en no bloqueante modo I/O. En modo no bloqueante, fallaría con el error EAGAIN o EWOULDBLOCK en este caso . La llamada de selección (2) se puede usar para determinar cuándo es posible enviar más datos.

+0

La página del manual es confusa: el comentario NO se aplica a los sockets SOCK_STREAM, solo a otros tipos. –

4

La respuesta está en otra sección de man 2 send:

When the message does not fit into the send buffer of the socket, 
    send() normally blocks, unless the socket has been placed in nonblock‐ 
    ing I/O mode. In nonblocking mode it would fail with the error EAGAIN 
    or EWOULDBLOCK in this case. The select(2) call may be used to deter‐ 
    mine when it is possible to send more data. 

O, alternativamente, la versión POSIX (man 3p send):

If space is not available at the sending socket to hold the message to 
    be transmitted, and the socket file descriptor does not have O_NONBLOCK 
    set, send() shall block until space is available. If space is not 
    available at the sending socket to hold the message to be transmitted, 
    and the socket file descriptor does have O_NONBLOCK set, send() shall 
    fail. The select() and poll() functions can be used to determine when 
    it is possible to send more data. 

Así, mientras que un read de los datos parciales son comunes , no debe producirse un send parcial en modo bloqueo (salvo detalles de implementación).

+0

La página del manual es confusa: el comentario NO se aplica a sockets SOCK_STREAM, solo a otros tipos –

+0

. Hay otra parte de la definición de la función que es relevante: "Si el mensaje es demasiado largo para pasar por el protocolo subyacente, envíe () fallará y no se transmitirán datos ", por lo que no recibirá envíos parciales en UDP. –