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.