Herr Groucho escribió:
Lautaro Cozzani escribió:
On 8/25/08, Herr Groucho <[EMAIL PROTECTED]> wrote:
Hola.
 Para resolver un problema, se me ha planteado la necesidad de hacer un
 programa que acepte conexiones TCP desde equipos embebidos y les lea
datos
 que dichos equipos están recabando en campo.

 Actualmente el programa de esos equipos embebidos establece la conexión
 TCP y la mantiene conectada todo el tiempo. Entonces el servidor que
 acepta esas conexiones va a tener un socket conectado con cada equipo
todo
 el tiempo. Si hay 10 equipos, tendrá 10 conexiones abiertas. Pero qué
pasa
 cuando hay 10000 equipos y por lo tanto 10000 conexiones?

 El programa que va a aceptar las conexiones actualmente lanza un
proceso
 hijo por cada conexión que acepta. Eso tiene la ventaja de que el
 tratamiento de TCP/IP y la implementación del protocolo de aplicación
se
 simplifica (sólo hay un socket del cual preocuparse y si el protocolo
de
 aplicación tiene que esperar un evento, directamente se puede bloquear
en
 un read() o write() o irse a dormir con timeout en un select()).
 Con 10000 conexiones, tendría 10001 procesos. Es esta una estrategia
 cuerda para manejar 10000 conexiones?

 - El sistema operativo soportará 10000 procesos (hace unos años el
tamaño
 de la tabla de procesos era elegido en tiempo de compilación del
kernel,
 en valores miserables como 200)?
 - El stack TCP/IP soportará 10000 conexiones?
 - Qué le pasará al consumo de memoria?
 - Qué le pasará al multitasking si el scheduler tiene que mirar una
tabla
 de procesos tan grande cada unas pocas decenas de milisegundos?


 Qué otras estrategias son concebibles?
 - Un único proceso que atienda y maneje todas las conexiones, usando
 arreglos para guardar los file descriptors de los sockets, select()
para
 esperar que pase algo interesante en alguno de ellos e iteraciones por
 todos lados?

 - Un proceso que lance hijos, cada uno de los cuales maneje unos pocos
 threads (un híbrido entre los 2)

 - Varios sistemas operativos independientes, corriendo en máquinas
(reales
 o virtuales) separadas ejecutando cada uno alguno de los programas
 anteriores.

 Sugerencias?
No se si podras usar la funcion select[1] de C para sockets, pero es
justamente para eso.

Sí, select() está mencionado entre una de las opciones en lo que escribí
más arriba. La pregunta es por qué debería usar esa opción en lugar de las
otras.

Otra opción que no mencioné porque me parece que es lo mismo que usar
fork() es usar threads, ya que para Linux, los threads igual ocupan
entradas en la tabla de procesos pues los ve como "procesos tomados con
liviandad".


¿Estás seguro de que los ve así a los threads? Tengo entendido que a partir de la inclusión de las NPTL cambió mucho ese aspecto, y los hilos comenzaron a ser algo más que procesos bloqueados por spinlocks. O más bien mucho menos que procesos. Si no me equivoco, cuando vos haces un fork, se duplica la imagen completa del mapa de memoria del proceso, pero no es así para los threads. Yo haría lo siguiente: programaría una aplicación de prueba que no hiciera nada util, pero que fuera capaz de atender a 10000 conexiones entrantes. La haría con fork y con la creación de nuevos threads (es decir, dos "bocetos" de aplicación distintos). También tendrías que hacer otro programa que cree las conexiones (el simulador de los controladores embebido). Después de eso, es cuestión de poner a andar la maquinaria y analizar en detalle los datos de los recursos consumidos por el servidor con alguna herramienta de profiling, o de la mejor forma que se te ocurra (lo más simple que se me viene a la mente es un "ps", pero debe haber algo mejor). Me da la impresión de que es medio rebuscado eso de poner varias máquinas en paralelo, o maquinas virtuales. Una sola debe ser suficientemente capaz de manejar esa cantidad (con la suficiente memoria y procesador, claro). Para mi, threads es el camino. Sino, usá solaris, que ahí si los hilos son hilos con todas las letras.

Federico.

Responder a