socket programming program how geeksforgeeks c coding-style send sockets

programming - socket.send c#



¿Por qué se supone que el envío puede retornar con menos de los datos solicitados transmitidos en un socket de bloqueo? (3)

Es un requisito bastante esencial para un mecanismo de transporte eficiente que involucre controladores de dispositivos. El rey de la pila es TCP, garantiza que no importa lo que le eches, hará su mejor nivel para que los datos se transmitan. Lo hace bastante bien, tiene una garantía de entrega de 9 nueves. Normalmente se requiere un terremoto o alguien que se tropiece con un cable de alimentación para no cumplir esa promesa.

Lo que significa que no tiene que preocuparse de que, cuando escriba datos en un socket, no se entregará. Lo que significa que el controlador del kernel puede tomarse la libertad de decir "¡Tengo espacio para almacenar esto, tráelo!" y le da al programa de modo de usuario un retorno rápido a cosas más importantes, como mantener la interfaz de usuario actualizada.

Buena cosa. Si por alguna razón su garantía de entrega necesita ser más fuerte que eso, quizás 12 nueves, entonces no debería usar TCP. Se ha hecho, "UDP fiable", de Google, bien. Aunque tiende a reinventarse una y otra vez. ¡Buena suerte!

El método estándar para enviar datos en un socket de flujo siempre ha sido enviar llamadas con una porción de datos para escribir, verificar el valor de retorno para ver si se enviaron todos los datos y luego seguir enviando de nuevo hasta que se haya aceptado todo el mensaje.

Por ejemplo, este es un ejemplo simple de un esquema común:

int send_all(int sock, unsigned char *buffer, int len) { int nsent; while(len > 0) { nsent = send(sock, buffer, len, 0); if(nsent == -1) // error return -1; buffer += nsent; len -= nsent; } return 0; // ok, all data sent }

Incluso la página de manual de BSD menciona que

... Si no hay espacio para mensajes disponible en el zócalo para retener el mensaje a transmitir, entonces, normalmente , send () bloquea ...

Lo que indica que debemos asumir que el envío puede devolverse sin enviar todos los datos. Ahora encuentro que esto está bastante roto, pero incluso W. Richard Stevens lo asume en su libro de referencia estándar sobre programación en red , no en los capítulos iniciales, pero los ejemplos más avanzados utilizan su propia función de escritura (escribir todos los datos) en lugar de llamar a escribir.

Ahora considero que esto todavía está más o menos roto, ya que si enviar no puede transmitir todos los datos o aceptar los datos en el búfer subyacente y el socket está bloqueando, entonces el envío debería bloquearse y devolverse cuando se haya aceptado toda la solicitud de envío. .

Quiero decir, en el ejemplo de código anterior, lo que sucederá si enviar devoluciones con menos datos enviados es que se volverá a llamar correctamente con una nueva solicitud. ¿Qué ha cambiado desde la última llamada? Al máximo, unos pocos cientos de ciclos de CPU han pasado, por lo que el búfer todavía está lleno. Si enviar ahora acepta los datos, ¿por qué no podría aceptarlo antes?

De lo contrario, terminaremos con un bucle ineficiente en el que estamos tratando de enviar datos en un socket que no puede aceptar datos y seguir intentando, ¿o si no?

Así que parece que la solución, si es necesario, resulta en un código muy ineficiente y, en esas circunstancias, se debe evitar el bloqueo de sockets, en su lugar se deben usar sockets sin bloqueo junto con select.


Esencialmente, el comportamiento solo agrega flexibilidad.

Considere qué sucede si los buffers de envío internos tienen espacio para otros 300 bytes, y le pide a send() que envíe 800 bytes.

Lo que suele suceder es que acepta los primeros 300 bytes y los coloca en el búfer de socket, luego los devuelve. Si realmente desea bloquear hasta que todos los 800 bytes se hayan ido, simplemente vuelva a llamar a send() para los últimos 500 bytes, y se bloqueará (ya que el búfer de envío ahora está lleno). Por otro lado, si desea hacer otra cosa ahora e intentar enviar los 500 bytes restantes más tarde, también puede hacerlo.


Lo que falta en la descripción anterior es que, en Unix, las llamadas al sistema pueden interrumpirse con las señales. Esa es exactamente la razón por la que el bloqueo de send(2) puede devolver un conteo corto.