Estoy trabajando en algún código Python modelado en el servidor prefork MPM de Apache. Soy más un programador de aplicaciones que un programador de redes y han pasado 10 años desde que leí a Stevens, así que estoy tratando de ponerme al día para entender el código.accept() con sockets compartidos entre procesos múltiples (basados en el preforking de Apache)
Encontré una breve descripción de how Apache's prefork code works, by Sander Temme.
El proceso principal, que normalmente se ejecuta como raíz, se une a un socket (normalmente el puerto 80 o 443). Engendra hijos, que heredan el descriptor de archivo abierto para el socket y cambian uid y gid al grupo y usuario sin privilegios . Los niños construyen un conjunto de encuestas de los descriptores de archivos de escucha (si hay más de un oyente) y vigilan la actividad en ellos. Si se encuentra actividad, el hijo llama al accept() en el socket activo y maneja la conexión. Cuando es hecho con eso, vuelve a mirar el conjunto de encuestas (o el archivo de escucha descriptor).
Dado que varios hijos están activos y todos ellos heredaron el mismo descriptor (es) del archivo de socket , estarán viendo el mismo conjunto de encuestas. Un aceptar mutex permite que solo un solo niño vea realmente el conjunto de polls, y una vez que haya encontrado un socket activo, desbloqueará el mutex para que el siguiente niño pueda comenzar a ver el conjunto de polls. Si solo hay un único oyente , acepte que no se utiliza mutex y todos los elementos secundarios se colgarán en accept().
Así es como funciona el código que estoy viendo, pero no entiendo algunas cosas.
1) ¿Cuál es la diferencia entre un "niño" y un "oyente"? Pensé que cada niño es un oyente, lo cual es cierto para el código que estoy viendo, pero en la descripción de Temme puede haber "un solo oyente" y "niños". ¿Cuándo un niño tendrá múltiples oyentes?
2) (Relacionados con 1) ¿Esto es un mutex por proceso o un mutex del sistema? Para el caso, ¿por qué tener un mutex? ¿No acepta (2) hacer su propio mutex en todos los oyentes? Mi investigación dice que necesito un mutex y que el mutex debe estar en todo el sistema. (Rebaño, semáforos, etc.)
Temme continúa diciendo:
niños registro en un área de memoria compartida (el marcador) cuando se agoten sirvió una solicitud. Los hijos inactivos pueden ser asesinados por el proceso principal al satisfacer MaxSpareServers. Si muy pocos niños están inactivos, el padre engendrará hijos para satisfacer MinSpareServers.
3) ¿Existe un buen código de referencia para esta implementación (preferiblemente en Python)? Encontré el Net::Server::Prefork de Perl, que usa tubos en lugar de memoria compartida para el marcador. Encontré un artículo por Randal Schwartz que solo hace los preparativos pero no hace el marcador.
El pre-fork example from the Perl Cookbook no tiene ningún tipo de bloqueo en torno a seleccionar, y Chris Siebenmann's Python example dice que está basado en Apache, pero utiliza sockets emparejados para el marcador, no se comparte la memoria y utilizar las tomas para los controles, incluir el control de un niño dado a 'aceptar. Esto no coincide con la descripción de Apache.
¿Estás utilizando algo como 'mod_wsgi' como interfaz entre Apache y Python? Si es así, debería manejar todo esto por ti. –
Esto es para un servidor WSGI de precodificación de Python puro. Mi cliente quiere una solución liviana para los lugares que no quieren Apache y mod_wsgi, o equivalente. El único servidor WSGI de Python que encontré fue el Spawn, y eso requiere eventlet. ... Aunque ahora descubrí que flup tiene una implementación como la de Siebenmann, que utiliza tuberías para el marcador en lugar de memoria compartida, y con una licencia aceptable para mi cliente. –