2009-04-11 5 views
6

Cuando se utiliza un socket TCP, lo que haceComportamiento de apagado (calcetín, SHUT_RD) con TCP

shutdown(sock, SHUT_RD); 

realmente? ¿Simplemente hace que todas las llamadas recv() devuelvan un código de error? Si es así, ¿qué código de error?

¿Hace que los paquetes sean enviados por la conexión TCP subyacente? ¿Qué ocurre con los datos que envía el otro lado en este momento? ¿Se conservan y el tamaño de la ventana de la conexión se reduce hasta llegar a 0, o simplemente se descarta, y el tamaño de la ventana no se reduce?

Respuesta

4

Apagado del lado de lectura del punto de separación causará ningún bloqueado recv (o similar) llama a volver 0 (lo que indica apagado correcto). No sé qué pasará con los datos que actualmente viajan por la pila de IP. Seguramente ignorará los datos que están en vuelo desde el otro lado. No afectará las escrituras en ese socket en absoluto.

De hecho, el uso juicioso de shutdown es una buena manera de asegurarse de que limpiar tan pronto como haya hecho. Un cliente HTTP que no use keepalive puede cerrar el lado de escritura tan pronto como termine de enviar la solicitud, y un servidor que vea Connection: closed también puede cerrar el lado de lectura tan pronto como haya terminado de recibir la solicitud. Esto hará que cualquier actividad errónea adicional sea inmediatamente obvia, lo cual es muy útil cuando se escribe código de nivel de protocolo.

2

Al mirar el código fuente de Linux, shutdown(sock, SHUT_RD) no parece causar ningún cambio de estado en el socket. (Obviamente, shutdown(sock, SHUT_WR) hace que se establezca FIN)

No puedo comentar sobre los cambios de tamaño de la ventana (o la falta de los mismos). Pero puedes escribir un programa de prueba para ver. Simplemente haga que su inetd ejecute un servicio chargen y conéctese. :-)

0

shutdown (calcetín, SHUT_RD) hace que cualquier escritor en el zócalo reciba una señal de sigpipe.

Cualquier lectura adicional que utilice la llamada al sistema de lectura devolverá -1 y establecerá errno en EINVAL.

El uso de recv devolverá un -1 y configurará errno para indicar el error (probablemente ENOTCONN o ENOTSOCK).

+0

¿por qué SHUT_RD afectaría a los escritores? No veo ninguna razón obvia para hacerlo (aunque supongo que siempre uso MSG_NOSIGNAL, por lo que puede tener un impacto). – Tom

+0

Porque (citando de Wikipedia) "En las plataformas que cumplen con POSIX, SIGPIPE es la señal enviada a un proceso cuando intenta escribir en un conducto sin un proceso conectado al otro extremo". Y la instrucción shutdown (calcetín, SHUT_RD) desconecta el proceso de lectura de la tubería. Para agregar daño por insulto, la acción predeterminada al recibir una señal SIGPIPE es que el proceso (es decir, el escritor) finalice. –

+0

Esto no es correcto. Cualquier lectura adicional hará que recv() vuelva a ejecutar cero, indicando el final del flujo. – EJP

3

shutdown (, SHUT_RD) no tiene ninguna contraparte en el protocolo TCP, por lo que depende de la implementación cómo comportarse cuando alguien escribe en una conexión donde el otro lado indicó que no leerá o cuando intente leer después de que declaraste que no.

En un nivel ligeramente inferior, es útil recordar que la conexión TCP es un par de flujos mediante el cual los pares envían datos hasta que declaran que están hechos (por SHUT_WR que envía FIN). Y estos dos flujos son bastante independientes.

0

Tiene dos efectos, uno de ellos depende de la plataforma.

  1. recv() devolverá cero, indicando final de corriente.
  2. Cualquier escritura adicional a la conexión por parte del par será (a) desechada silenciosamente por el receptor (BSD), (b) será amortiguada por el receptor y eventualmente causará que send() bloquee o devuelva -1/EAGAIN/EWOULDBLOCK (Linux), o (c) causa que el receptor envíe un RST (Windows).
1

Pruebo shudown(sock,SHUT_RD) en Ubuntu 12.04. Encuentro que cuando llamas al shutdown(sock,SHUT_RD) si no hay ningún tipo de datos (incluye FIN ....) en el búfer TCP, la llamada de lectura sucesiva será return 0 (indica el final del flujo). Pero si hay algunos datos que llegaron antes o después de la función de apagado, leer la llamada se procesará normalmente como si no se hubiera llamado a la función de apagado. Parece que shutdown(sock,SHUT_RD) no causa ningún estado TCP cambiado al socket