Title: Qu
1Qué pasa cuando varios clientes tratan de
conectarse al mismo teimpo a un servidor
- Una forma es ir atendiéndolos de a uno en un
ciclo como en el programa que atiende pedidos de
archivos - Se acepta una conexión
- se lee la petición
- se lee desde el
- archivo y se escribe en el socket hasta encontrar
una marca de fin de archivo - A este tipo de servidores se les llama servidores
iterativos - El problema es que todo cliente tiene que esperar
su turno para ser atendido - Si uno de ellos pide un archivo muy grande los
demás tienen que esperar - La mayor parte de la espera es debido a
operaciones de IO, hay capacidad de CPU ociosa !
2Un Servidor Concurrente
- Un servidor concurrente atiende a varios clientes
al mismo tiempo. - Más aún, mientras está atendiendo sigue
escuchando - El problema es que todo cliente tiene que esperar
su turno para ser atendido - Si uno de ellos pide un archivo muy grande los
demás tienen que esperar - La mayor parte de la espera es debido a
operaciones de IO, hay capacidad de CPU ociosa ! - Se trata de crear un nuevo proceso o línea de
ejecución cada vez que un cliente llega a pedir
un servicio.
3Algoritmo de Servidor Concurrente
- Programa principal o master del servidor
- 1- Crear un Socket de servidor
- En un ciclo infinito
- 2- aceptar requerimientos de clientes
- 3- cuando llega una petición de un cliente
crear un nuevo - proceso esclavo que atienda
paralelamente la petición - (esto no debe bloquear la ejecución del
programa master - del servidor)
- 4 - volver a 2.
- Proceso esclavo
- 1- Recibir los parámetros de la comunicación
(socket o flujos de entrada y/o salida) - 2- Atender al cliente (ej leer el nombre del
archivo, transmitir el archivo) - 3- Retornar (desaparecer !)
4Cómo (y por qué) crear procesos paralelos
- Si existe sólo una CPU, Por qué crear procesos
paralelos? - Porque algunos programas se escriben más
fácilmente así. De hecho, la programación de un
servidor es a veces más fácil si se hace de esta
manera. - Porque sí hay más de un procesador !!!!!
(dónde?) - El concepto de procesos paralelos implentados a
nivel de S.O. aparecen con UNIX y C. - La forma de crearlos es ejecutando una función
llamada fork() - int i fork() provoca que se cree un proceso
exactamente igual al que se está ejecutando. - La única diferencia es que en el proceso hijo (el
nuevo creado) la variable i vale cero. Esto se
usa para saber quién soy yo. - En programación de servidores concurrentes, si
soy el hijo ejecuto la parte que corresponde al
proceso esclavo. - Si soy el padre (i tiene un valor distinto de
cero y es el id del proceso hijo creado) sigo
recibiendo peticiones
5Ejemplo de procesos paralelos en C (muy
simplificado)
- main()
- int pid, msock, ssock
- sock passivesock(port, tcp, qlen)
- / ver capítulo 10.4 del libro Internetworking
with tcp/ip de Douglas Commer para ver cómo se
implementa / - while(1)
- ssock accept(msock, fsin, alen)
- pid fork()
- if (pid 0)
- atender al cliente
- retornar
-
6Problemas con el fork() en UNIX
- La creación del proceso paralelo es costosa en
tiempo. - En algunos textos se sugiere que se podrían crear
los procesos paralelos al levantar el servidor.
Cuando llegue un cliente simplemente se le pasan
los datos por medio de un pipe que se crea entre
el proceso padre y el proceso hijo - El proceso paralelo duplica exactamente todo el
ambiente en el cual estaba corriendo el proceso
original, incluso aquellas variables que no
necesita !!! - No es fácil manejar procesos paralelos, ya que si
no se terminan en forma normal pueden quedar
consumiendo recursos indefinidamente. - La única información que tiene el padre para
controlarlos es su identificación al crearlos. - Muchas veces se prefiere usar el método select,
que lo que hace es preguntar de una serie de
puntos de lectura de datos (en este caso sockets)
cuál está listo para ser leído este puede ser
uno de los sockets de comunicación con cliente
(en un arreglo) o el socket por donde se escuchan
las peticiones (recordar que el IO es lo más
lento en todo esto)
7En JAVA se prefiere usar Threads
- Un thread es una secuencia o flujo de de
instrucciones que se ejecutan dentro de un
programa. Tiene un comienzo y un fin. Entonces
qué diferencia tiene con un proceso ? - El thread sólo puede ser creado dentro de un
proceso. Y un proceso (programa) puede crear
varios threads dentro de él que se ejecutan en
paralelo. - Entonces, qué diferencia tiene con el fork(). El
programa principal está conciente de los
threads que existen, hay variables que los
identifican. Pueden ser creados, inicializados,
sustendidos, reactivados o parados por el el
programa que los creó. - El programa principal puede darles parámetros
distintos a cada thread. Los thread se pueden
programar con la canatidad de variables
necesarias para su ejecución (no lo heredan TODO)
8Usando threads para atender multiples clientes de
un Servidor de Sockets
- La forma de implementar servidores que atiendan a
varios clientes paralelamente a la vez es
combinando threads con sockets - El servidor abre un ServerSocket desde donde oye
ciualquier intento por conectarse con él de un
cliente. - Una vez establecida la conexión, abre un socket
normal e inicia un thread que atiende a este
cliente. El socket abierto se pasa como
parámetro. De esa manera puede seguir oyendo por
el ServerSocket sin estar bloqueado. - El thread tiene un método run que atiende los
pedidos del cliente - El cliente se conecta al servidor sin saber que
finalmente será un socket el que está
atendiéndolo.
9Implementación de Threads
- Una forma de usar Threads en Java es creando una
nueva clase que extienda la clase Thread y
sobreescribir el método run. - Los threads son una clase existente. Esta clase
se debe extender para hacer una clase derivada
que haga lo que nosotros queramos. - Lo que un thread en particular hace cuando se
echa a correr se programa en un método llamado
run de la clase extendida de Thread.. - El método run ejecuta cuando a un objeto de esta
clase se le aplica el método start() - El encabezado de una clase Thread será
- public class MiThread extends Thread
- Y en alguna parte deberá aparecer
- public void run()
- //aquí va lo que queremos que se haga en paralelo
10Ejemplo de Threads Como clase nueva
- public class SimpleThread extends Thread
- public SimpleThread(String str)
- super(str)
-
- public void run()
- for (int i 0 i lt 10 i)
- System.out.println(i " "
getName()) - try
- this.sleep((int)(Math.ra
ndom() 1000)) - catch (InterruptedExceptio
n e) -
- System.out.println("DONE! "
getName()) -
-
- El método this.sleep(milisegundos) debe ir en un
bloque try and catch
11Ejemplo de Threads Uso de la clase nueva
- public class TwoThreadsTest
- public static void main (String
args) - SimpleThread t1,t2
- t1 SimpleThread("Jamaica")
- t2 SimpleThread("Fiji")
- t1.start() t2.start()
-
-
- El método start() inicia la ejecucón de un
thread. Esto implica que se empieza a ejecutar el
código escrito en el método run del thread.
También existen otros métodos que se le pueden
aplicar a un thread suspend(), resume(), stop().
12Qué pasa no se puede usar extends?
- Si el servidor también tiene una interfaz gráfica
(extends Frame) o está en un applet (extends
Applet) no puede a la vez extender el thread - Se usa la implementación de la interfaz Runnable,
lo que implica que la clase debe implementar el
método run(). - Para iniciar una ejecución paralela del método
run se debe crear un objeto de la clase Thread,
al cual se le pasa como parámetro el objeto
servidor (con lo cual también tiene acceso a sus
recursos) - El método run del servidor se ejecuta cuando se
aplica el método start() sobre el objeto Thread
recién creado.
13Ejemplo implementar Runnable
- Ver (y ejecutar) programa NoSincron.java
- De esta forma se comparte obligadamente los
recursos del servidor entre todos los procesos
esclavos - De la otra forma es más bien una opción, (pasar
un puntero al servidor cuando se crea un objeto
thread) - De cualquier forma, será frecuente el compartir
recursos y por lo tanto la admistración de ellos
es importante
14Regiones críticas y semáforos en Java
- Java provee estos dos mecanismos para controlar
elacceso a datos compartidos de modo que haya un
solo tread ejecutando un pedazo de código - Se puede declarar un método enterocomo región
crítica (ver sincron1) - Se puede usar el semáforo que cada objeto posee
(ver sincron2)
15Cómo usar threads para hacer servidores
concurrentes
- Hacer una clase Thread que tenga como variables
de un objeto un socket y flujos de entrada y/o
salida. - Programar el constructor de modo que reciba como
parámetro un socket y haga todo lo necesario para
dejar inicializado el ambiente para empezar a
atender al cleinte (por ejemplo, abrir flujos de
datos de entrada y/o salida del socket recibido) - Programar el método run de modo que implemente el
protocolo necesario. - Programar un método main que en un ciclo infimito
se ponga a escuchar en un port dado la llegada de
clientes. - Con cada cliente nuevo crear un thread nuevo y
pasar como parámetro el socket
MultiFileServer
MultiFileThread
16Programemos algo bien simple
Bla bla from keyboard
Bla bla
Talk Server
Talk client
17Programemos algo no tan simple
Bla bla
Talk client
Talk Server
Talk client
Talk Server
Bla bla
- Cualquiera puede iniciar la llamada
- Cuando esta contestando no puede llamar
- Cuando está llamando no puede contestar
- Por ahora, sólo el servidor puede mandar
mensajes