You are on page 1of 17

Qu pasa cuando varios clientes tratan

de conectarse al mismo teimpo a un


servidor
Una forma es ir atendindolos de a uno en un ciclo: como en el programa
que atiende pedidos de archivos

Se acepta una conexin


se lee la peticin
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 dems tienen que esperar
La mayor parte de la espera es debido a operaciones de IO, hay capacidad
de CPU ociosa !

Un Servidor Concurrente
Un servidor concurrente atiende a varios clientes al mismo
tiempo.
Ms an, 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 dems 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 lnea de ejecucin cada vez
que un cliente llega a pedir un servicio.

Algoritmo 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 peticin de un cliente crear un nuevo
proceso esclavo que atienda paralelamente la peticin
(esto no debe bloquear la ejecucin del programa master
del servidor)
4 - volver a 2.
Proceso esclavo
1- Recibir los parmetros de la comunicacin (socket o flujos de entrada
y/o salida)
2- Atender al cliente (ej: leer el nombre del archivo, transmitir el archivo)
3- Retornar (desaparecer !)

Cmo (y por qu) crear procesos


paralelos
Si existe slo una CPU, Por qu crear procesos paralelos?
Porque algunos programas se escriben ms fcilmente as. De hecho,
la programacin de un servidor es a veces ms fcil si se hace de
esta manera.
Porque s hay ms de un procesador !!!!! (dnde?)

El concepto de procesos paralelos implentados a nivel de S.O.


aparecen con UNIX y C.
La forma de crearlos es ejecutando una funcin 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 quin soy yo.
En programacin 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

Ejemplo de procesos paralelos en C


(muy simplificado)
main() {
int pid, msock, ssock;
sock = passivesock(port, tcp, qlen);
/* ver captulo 10.4 del libro Internetworking with tcp/ip de Douglas
Commer para ver cmo se implementa */

while(1) {
ssock = accept(msock, &fsin, &alen);
pid = fork();
if (pid == 0) {
atender al cliente;
retornar;
}

Problemas con el fork() en UNIX


La creacin del proceso paralelo es costosa en tiempo.

En algunos textos se sugiere que se podran 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 fcil manejar procesos paralelos, ya que si no se terminan en
forma normal pueden quedar consumiendo recursos indefinidamente.
La nica informacin que tiene el padre para controlarlos es su
identificacin al crearlos.
Muchas veces se prefiere usar el mtodo select, que lo que hace es
preguntar de una serie de puntos de lectura de datos (en este caso
sockets) cul est listo para ser ledo: este puede ser uno de los sockets
de comunicacin con cliente (en un arreglo) o el socket por donde se
escuchan las peticiones (recordar que el IO es lo ms lento en todo esto)

En 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 slo 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 parmetros distintos a cada
thread. Los thread se pueden programar con la canatidad de
variables necesarias para su ejecucin (no lo heredan TODO)

Usando 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 conexin, abre un socket normal e
inicia un thread que atiende a este cliente. El socket abierto
se pasa como parmetro. De esa manera puede seguir
oyendo por el ServerSocket sin estar bloqueado.
El thread tiene un mtodo run que atiende los pedidos del
cliente
El cliente se conecta al servidor sin saber que finalmente
ser un socket el que est atendindolo.

Implementacin de Threads
Una forma de usar Threads en Java es creando una nueva clase
que extienda la clase Thread y sobreescribir el mtodo 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 mtodo llamado run de la clase extendida de Thread..
El mtodo run ejecuta cuando a un objeto de esta clase se le aplica el
mtodo 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 }

Ejemplo de Threads: Como clase nueva


public class SimpleThread extends Thread {
public SimpleThread(String str) {
super(str);
}

public void run() {


for (int i = 0; i < 10; i++) {
System.out.println(i + " " + getName());
try {
this.sleep((int)(Math.random() * 1000));
} catch (InterruptedException e) {}
}
System.out.println("DONE! " + getName());
}

El mtodo this.sleep(milisegundos) debe ir en un bloque try and catch

Ejemplo 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 mtodo start() inicia la ejecucn de un thread. Esto implica
que se empieza a ejecutar el cdigo escrito en el mtodo run
del thread. Tambin existen otros mtodos que se le pueden
aplicar a un thread: suspend(), resume(), stop().

Qu pasa no se puede usar extends?


Si el servidor tambin tiene una interfaz grfica
(extends Frame) o est en un applet (extends Applet)
no puede a la vez extender el thread
Se usa la implementacin de la interfaz Runnable, lo
que implica que la clase debe implementar el mtodo
run().
Para iniciar una ejecucin paralela del mtodo run se
debe crear un objeto de la clase Thread, al cual se le
pasa como parmetro el objeto servidor (con lo cual
tambin tiene acceso a sus recursos)
El mtodo run del servidor se ejecuta cuando se aplica
el mtodo start() sobre el objeto Thread recin creado.

Ejemplo: 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 ms bien una opcin,
(pasar un puntero al servidor cuando se crea
un objeto thread)
De cualquier forma, ser frecuente el
compartir recursos y por lo tanto la
admistracin de ellos es importante

Regiones crticas y semforos en Java


Java provee estos dos mecanismos para
controlar elacceso a datos compartidos de
modo que haya un solo tread ejecutando un
pedazo de cdigo
Se puede declarar un mtodo enterocomo
regin crtica (ver sincron1)
Se puede usar el semforo que cada objeto
posee (ver sincron2)

Cmo 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 parmetro
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 mtodo run de modo que implemente el
protocolo necesario.
Programar un mtodo 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
parmetro el socket

MultiFileServer MultiFileThread

Programemos algo bien simple


Bla bla from keyboard

Bla bla
Talk client

Talk Server

Programemos algo no tan simple


Talk client

Bla bla

Talk Server

Talk Server
Talk client

Bla bla

Cualquiera puede iniciar la llamada


Cuando esta contestando no puede llamar
Cuando est llamando no puede contestar
Por ahora, slo el servidor puede mandar mensajes

You might also like