linux posix sockets listen

linux - ¿Es posible desligarse de un zócalo?



posix sockets (11)

¡No hay un método explícito para desvincularse!

Puede close(fd) o shutdown(fd, how)

fd is the socket file descriptor you want to shutdown, and how is one of the following: 0 Further receives are disallowed 1 Further sends are disallowed 2 Further sends and receives are disallowed (like close())

¿Es posible desconectarse de un socket después de haber llamado listen (fd, backlog)?

Editar: Mi error por no haber sido claro. Me gustaría poder desconectarme temporalmente en el zócalo. Llamar a close () dejará el socket en el estado M2LS e impedirá que vuelva a abrirlo (o peor, algún programa nefasto podría vincularse a ese socket)

Desactivar temporalmente podría ser una forma (quizás no la mejor) para indicar a un equilibrador de carga en sentido ascendente que esta aplicación no podría aceptar más solicitudes por el momento


Cierralo. Hasta donde recuerdo;

close(fd);


Después de cerrar el zócalo, es posible que sus programas aún le digan que el zócalo está "en uso", esto se debe a una rareza que no conozco exactamente. Pero la página de manual sobre sockets muestra que hay una bandera para reutilizar el mismo socket, llamado de forma perezosa: "SO_REUSEADDR". Configúrelo usando "setsockopt ()".


En un nivel básico, los sockets están abiertos o cerrados (ignoraremos las sutilezas del diagrama de estado TCP / IP aquí).

Si su socket está cerrado, entonces nada puede enviarle datos. Si está abierto, los datos entrantes serán aceptados y confirmados por la pila TCP / IP hasta que el algoritmo de almacenamiento intermedio grite "¡suficiente!". En ese momento, no se reconocerán más datos.

Tienes dos opciones que puedo ver. Cierre () el socket cuando desee "unlisten" y vuélvalo a abrir más tarde: use setsockopt () con el indicador SO_REUSEADDR para permitirle volver a vincular al puerto conocido antes de que caduque TIME_WAIT2.

La otra opción es mantener el socket abierto pero simplemente no aceptar () mientras está ''ocupado''. Suponiendo que tiene un reconocimiento de nivel de aplicación a las solicitudes, el equilibrador de carga se daría cuenta de que no está recibiendo una respuesta y actuará en consecuencia.


Según su versión editada de la pregunta, no estoy seguro de que tenga que "desconectarse" o cerrar (). Dos opciones vienen a la mente:

1) Después de invocar listen (), las conexiones no son realmente aceptadas hasta que (lógicamente) llame a accept (). Puede "desconectarse" simplemente ignorando la actividad del socket y difiriendo cualquier accept () hasta que esté listo para ellos. Cualquier conexión entrante intenta atrasarse en la cola que se creó cuando el puerto se abrió en el modo de escucha. Una vez que la cola de cola de espera está llena en la pila, los intentos de conexión adicionales simplemente se dejan caer en el suelo. Cuando reanude con accept (), rápidamente dequeue la acumulación y estará listo para más conexiones.

2) Si realmente desea que el puerto aparezca completamente cerrado temporalmente, puede aplicar dinámicamente el filtro de paquete de nivel de kernel al puerto para evitar que los intentos de conexión entrante lleguen a la pila de red. Por ejemplo, puede usar Berkeley Packet Filter (BPF) en la mayoría de las plataformas * nix. Eso es lo que desea hacer con los paquetes entrantes que ingresan al puerto de interés utilizando las funciones de firewall de la plataforma. Esto, por supuesto, varía según la plataforma, pero es un enfoque posible.


Este es un enfoque bastante feo basado en su pregunta editada:

Abra un socket para escuchar con un retraso acumulado normal. Proceder.

Cuando desee "cerrar", abra un 2º con una acumulación de 1 y SO_REUSEADDR. Cierra el primero. Cuando esté listo para reanudar, haga otro zócalo de malabares con uno con un retraso acumulado normal.

Detalles complicados sobre cómo agotar la cola de aceptación del socket que está cerrando serán los asesinos aquí. Probablemente lo suficiente de un asesino para hacer que este enfoque no sea viable.


No creo necesariamente que sea una buena idea, pero ...

Es posible que pueda llamar a escuchar por segunda vez. La especificación POSIX no dice no a. Quizás podría llamarlo por segunda vez con un parámetro de acumulación de 0 cuando desee "desconectar".

Lo que ocurre cuando se llama a escuchar con un retraso de 0 parece ser una implementación definida. La especificación POSIX dice que puede permitir que se acepten conexiones, lo que implica que algunas implementaciones pueden optar por rechazar todas las conexiones si el parámetro de retraso acumulado es 0. Sin embargo, su implementación elegirá algún valor positivo cuando pase en 0 (probablemente sea 1 o SOMAXCONN).


No creo que sea una buena forma de señalizar un equilibrador de carga en sentido ascendente. En realidad, tendría que enviar algunas conexiones a su servidor antes de que el mensaje llegara a su fin; esas conexiones probablemente serían rechazadas.

Del mismo modo, las conexiones que estaban pendientes cuando cerró el socket de escucha se cerrarán sin datos.

Si desea señalizar el balanceador de carga ascendente, debe tener un protocolo para hacerlo. No intente abusar de TCP para hacerlo.

Afortunadamente, si los clientes son navegadores web normales, puede salirse con la suya con un montón de cosas: simplemente cerrar los sockets generalmente hace que vuelvan a intentar de forma transparente para el usuario (hasta cierto punto).


La pregunta no decía qué tipo de zócalo. Si es un socket unix, puede detenerse y comenzar a escuchar con rename (2). También puede dejar de escuchar permanentemente con unlink (2), y dado que el socket permanece abierto, puede continuar atendiendo su backlog. Este enfoque parece bastante útil, aunque no he visto antes y estoy explorando por mi cuenta.


Ya tienes algunas respuestas sobre la imposibilidad de hacer esto a través de la API de socket.

Puede usar otros métodos de sistema operativo (es decir, Host firwewall / iptables / ipfilter) para configurar una regla de rechazo temporal.

Descubrí que la mayoría de los equilibradores de carga están un poco limitados en cuanto a las posibilidades que ofrecen para reconocer problemas de conexión (la mayoría de ellos reconoce un RST solo en la sonda de conexión, no como respuesta a un intento de conexión legítimo).

De todos modos, si está limitado por las sondas que detectan la inaccesibilidad, configure una sonda de nivel de aplicación que realice una solicitud HTTP o un inicio de sesión FTP o cosas similares que reconocerá si simplemente cierra después de aceptar. Incluso podría interpretar mensajes de error como "500 servicio no disponible", que de todos modos me parece más limpio. Con SNMP algunos balanceadores de carga también pueden usar el resultado como una sugerencia de carga.


Algunas bibliotecas de socket le permiten rechazar específicamente las conexiones entrantes. Por ejemplo: CommonC ++ de GNU: la clase TCPsocket tiene un método de rechazo .

BSD Sockets no tiene esta funcionalidad. Puede aceptar la conexión y luego cerrarla inmediatamente, mientras deja el socket abierto:

while (running) { int i32ConnectFD = accept(i32SocketFD, NULL, NULL); while (noConnectionsPlease) { shutdown(i32ConnectFD, 2); close(i32ConnectFD); break; } }