Indice general de los manuales

  1. Introducción, instalación en Ubuntu y creación de una calculadora.
  2. Modos de compartición de objetos. Creando nuestra primera calculadora distribuida.
    1. Modos de compartición de objetos: Singlecall.
    2. Modos de compartición de objetos: Singleton.
    3. Modos de compartición de objetos: CAO.  «  [Leyendo]
  3. Canales: TCP y HTTP. Configuración en archivo XML.
  4. Uso de interfaces para separar el código entre cliente y servidor.

CAO

La última de las formas de compartir los objetos desde el servidor es CAO: Client Activated Object. De esta forma, cada cliente que acceda al servidor, podrá crear un objeto en el y usarlo de forma independiente. En nuestro ejemplo, cada cliente tendrá su propia calculadora.

cao

Como vemos, cada cliente tiene su propia calculadora, y cada calculadora guarda su estado.

Aunque el nuevo código del servidor es muy parecido a los anteriores, pongo el cuerpo de Main entero:

  1. // Archivo: Servidor.cs
  2. // Descripcion: programa servidor que comparte
  3. // la clase Calculadora remotamente.
  4.  
  5. // Biblioteca estandar y remoting
  6. using System;
  7. using System.Runtime.Remoting;
  8.  
  9. // Bibliotecas para usar un canal HTTP
  10. using System.Runtime.Remoting.Channels;
  11. using System.Runtime.Remoting.Channels.Http;
  12. using Calculo;
  13.  
  14. public class Servidor
  15. {
  16.   // arg[0] representa el puerto del servidor
  17.   public static void Main (string[] args)
  18.   {
  19.     // Creamos un nuevo objeto para el canal HTTP
  20.     HttpChannel chnl = new HttpChannel(int.Parse(args[0]));
  21.  
  22.     // Le decimos a la máquina que nos reserve ese canal
  23.     ChannelServices.RegisterChannel(chnl);
  24.     
  25.     // Opciones para la comparticion de la clase
  26.     RemotingConfiguration.ApplicationName =
  27.        “ServidorDeCalculadoras”;
  28.     RemotingConfiguration.RegisterActivatedServiceType(
  29.       typeof(Calculo.Calculadora));
  30.  
  31.     // Mensajes de espera en la pantalla
  32.     Console.WriteLine(“Atendiendo las peticiones…”);
  33.     Console.WriteLine(“Pulse Enter para salir…”);
  34.     Console.ReadLine();
  35.   }
  36. }

La configuración del servidor la hemos dividido en dos partes, le hemos adjudicado un nombre que será el del servidor, no el de una calculadora; y después hemos compartido la calculadora.

Vamos a modificar el cliente por completo, para que no tengamos que hacer dos clientes diferentes para ver el funcionamiento de esta forma de compartir.

  1. // Archivo: Cliente.cs
  2. // Version: 2.0
  3. // Descripcion: cliente que usara la clase remota Calculadora
  4.  
  5. // Biblioteca estandar y remoting
  6. using System;
  7. using System.Runtime.Remoting;
  8.  
  9. // Bibliotecas para usar un canal HTTP
  10. using System.Runtime.Remoting.Channels;
  11. using System.Runtime.Remoting.Channels.Http;
  12. using Calculo;
  13.  
  14. public class Cliente
  15. {
  16.   // arg[0] representa el host del servidor
  17.   // arg[1] representa el puerto del servidor
  18.   // arg[2] representa el numero que guardamos en LaBase
  19.   public static void Main (string[] args)
  20.   {
  21.     // Creamos un nuevo objeto para el canal HTTP
  22.     HttpChannel chnl = new HttpChannel();
  23.  
  24.     // Le decimos a la máquina que nos reserve ese canal
  25.     ChannelServices.RegisterChannel(chnl);
  26.  
  27.     // Opciones para la utilizacion remota de la clase
  28.     RemotingConfiguration.RegisterActivatedClientType(
  29.       typeof(Calculo.Calculadora),
  30.       “http://” + args[0] + “:” + args[1]);
  31.  
  32.     // Creamos un objeto
  33.     Calculadora calc = new Calculadora();
  34.  
  35.     // Practicamos
  36.     calc.LaBase = int.Parse(args[2]);
  37.     Console.WriteLine(“Cambiado a: “ + cacl.LaBase);
  38.  
  39.     Console.WriteLine(“Pulse Enter para ver el estado…”);
  40.     Console.ReadLine();
  41.  
  42.     Console.WriteLine(“Hemos cambiado la base a “ + calc.LaBase);
  43.   }
  44. }

 

Podemos ver varios cambios en este nuevo cliente:

  • A diferencia de los anteriores, solo necesitamos saber el host y el puerto del servidor, no nos hace falta saber el nombre con el que el servidor se ha autodenominado.
  • Hemos añadido un nuevo argumento al ejecutar el programa, que será el número que queremos adjudicar a LaBase, y así poder hacer varias pruebas para cambiar el estado desde el cliente sin tener que crear dos.
  • Para comprobar que cada cliente tiene su propia calculadora, hemos interrumpido el programa a la mitad (pulsando Enter) para cambiar el estado desde dos clientes diferentes que se ejecutan a la misma vez y comprobar después que cada uno tiene una calculadora con su propio estado.

Ahora solo nos queda compilar los archivos:

mcs -target:library Calculo.cs
mcs -r:Calculo.dll -r:System.Runtime.Remoting.dll Servidor.cs
mcs -r:Calculo.dll -r:System.Runtime.Remoting.dll Cliente.cs

Ejecutaremos los archivos en diferentes consolas:

Ejecutar el servidor:

./Servidor.exe 9999

El cliente 1:

./Cliente.exe localhost 9999 5

Y su resultado:

Cambiado a: 5
Pulse Enter para ver el estado…

Y el cliente 2:

./Cliente2.exe localhost 9999 8

Y su resultado:

Cambiado a: 8
Pulse Enter para ver el estado…

Una vez que tenemos los dos clientes cargados, pulsamos Enter en cada uno de ellos y vemos que conservan su estado:

El Cliente 1:

Hemos cambiado la base a 5

El Cliente 2:

Hemos cambiado la base a 8

En el servidor solo veremos como cada cliente crea un nuevo objeto.

Atenciando las peticiones…
Pulse Enter para salir…
Contructor.
Constructor.

Ya que cada cliente puede crearse su propia calculadora, podríamos replantearnos dejar que cada objeto “muera” pasado un tiempo (el tiempo de vida que vimos en el capítulo anterior) o controlar todas las instancias que se hacen desde los servidores con un atributo estático que vaya aumentando por cada instancia. Deberíamos pensar esto ya que puede que alguien malintencionado haga miles de clientes que llamen a nuestro servidor, creando miles de instancias y bloqueando el servidor.

Aunque ya está escrita la parte más importante del manual, en los siguientes capítulos veremos trucos y formas de usar la teoría que hemos dado hasta ahora.

El código fuente de uno de los comentarios expuestos abajo, se encuentra aquí.

Indice general de los manuales

  1. Introducción, instalación en Ubuntu y creación de una calculadora.
  2. Modos de compartición de objetos. Creando nuestra primera calculadora distribuida.
    1. Modos de compartición de objetos: Singlecall.
    2. Modos de compartición de objetos: Singleton.
    3. Modos de compartición de objetos: CAO.  «  [Leyendo]
  3. Canales: TCP y HTTP. Configuración en archivo XML.
  4. Uso de interfaces para separar el código entre cliente y servidor.

Indice general de los manuales

  1. Introducción, instalación en Ubuntu y creación de una calculadora.
  2. Modos de compartición de objetos. Creando nuestra primera calculadora distribuida.
    1. Modos de compartición de objetos: Singlecall.
    2. Modos de compartición de objetos: Singleton.  «  [Leyendo]
    3. Modos de compartición de objetos: CAO.
  3. Canales: TCP y HTTP. Configuración en archivo XML.
  4. Uso de interfaces para separar el código entre cliente y servidor.

Singleton

Ésta es otra de las formas que vimos en las que el servidor puede compartir un objeto. De esta forma el servidor creará un objeto único para todos los clientes y podrá guardar el estado. Así, los clientes podrán compartir información de ese objeto entre ellos.

singleton

Como podemos ver, los clientes comparten la misma calculadora. El cliente1 cambia uno de los atributos del objeto (cambia el estado) y el cliente2 se percata de ello.

El código del servidor es igual que el del tutorial anterior, aunque solo habrá que decirle que comparta la calculadora en modo Singleton. Modificaremos la siguiente línea:

  1. // Archivo: Servidor.cs
  2. // Descripcion: programa servidor que comparte
  3. // la clase Calculadora remotamente.
  4.  
  5. // Biblioteca estandar y remoting
  6. using System;
  7. using System.Runtime.Remoting;
  8.  
  9. // Bibliotecas para usar un canal HTTP
  10. using System.Runtime.Remoting.Channels;
  11. using System.Runtime.Remoting.Channels.Http;
  12. using Calculo;
  13.  
  14. public class Servidor
  15. {
  16.   // arg[0] representa el puerto del servidor
  17.   public static void Main (string[] args)
  18.   {
  19.     // Creamos un nuevo objeto para el canal HTTP
  20.     HttpChannel chnl = new HttpChannel(int.Parse(args[0]));
  21.  
  22.     // Le decimos a la máquina que nos reserve ese canal
  23.     ChannelServices.RegisterChannel(chnl);
  24.  
  25.     // Opciones para la comparticion de la clase
  26.     RemotingConfiguration.RegisterWellKnownServiceType(
  27.       typeof(Calculo.Calculadora),
  28.       “Calculadora.remota”,
  29.       WellKnownObjectMode.Singleton);
  30.  
  31.     // Mensajes de espera en la pantalla
  32.     Console.WriteLine(“Atendiendo las peticiones…”);
  33.     Console.WriteLine(“Pulse Enter para salir…”);
  34.     Console.ReadLine();
  35.   }
  36. }

Y el cliente lo dejaremos igual, ya que en el cliente no especificábamos como era la forma en la que compartía el servidor. Aunque vamos a crear otro nuevo servidor para ver como se comparte el objeto entre los dos. Solo escribiré la parte en que se hace uso de la calculadora, el resto del código (crear canal HTTP, reservar el canal, forma en la que se comparte) será igual:

  1. // Archivo: Cliente2.cs
  2. // Descripcion: cliente que usara la clase remota Calculadora
  3.  
  4. // Biblioteca estandar y remoting
  5. using System;
  6. using System.Runtime.Remoting;
  7.  
  8. // Bibliotecas para usar un canal HTTP
  9. using System.Runtime.Remoting.Channels;
  10. using System.Runtime.Remoting.Channels.Http;
  11. using Calculo;
  12.  
  13. public class Cliente2
  14. {
  15.   // arg[0] representa el host del servidor
  16.   // arg[1] representa el puerto del servidor
  17.   public static void Main (string[] args)
  18.   {
  19.     // Creamos un nuevo objeto para el canal HTTP
  20.     HttpChannel chnl = new HttpChannel();
  21.  
  22.     // Le decimos a la máquina que nos reserve ese canal
  23.     ChannelServices.RegisterChannel(chnl);
  24.  
  25.     // Opciones para la utilizacion remota de la clase
  26.     RemotingConfiguration.RegisterWellKnownClientType(
  27.       typeof(Calculo.Calculadora),
  28.       “http://” + args[0] + “:” + args[1] + “/Calculadora.remota”);
  29.  
  30.     // Ahora, usamos la calculadora como si la clase
  31.     // la tuvieramos en nuestro ordenador
  32.     Calculadora calc = new Calculadora();
  33.     Console.WriteLine(“LaBase la hemos cambiado desde el primer cliente…”);
  34.     Console.WriteLine(“Asi que vemos que la base desde el segundo es: “ + calc.LaBase);
  35.    }
  36. }

El código del primer cliente lo podemos conseguir desde el tutorial anterior: Programación con C# y .NET Remoting/Mono Remoting [3/7]

Ahora solo nos queda compilar los archivos:

mcs -target:library Calculo.cs
mcs -r:Calculo.dll -r:System.Runtime.Remoting.dll Servidor.cs
mcs -r:Calculo.dll -r:System.Runtime.Remoting.dll Cliente.cs
mcs -r:Calculo.dll -r:System.Runtime.Remoting.dll Cliente2.cs

Ejecutaremos los archivos en diferentes consolas y con el siguiente orden.

Ejecutar el servidor:

./Servidor.exe 9999

El cliente 1:

./Cliente.exe localhost 9999

Y el cliente 2:

./Cliente2.exe localhost 9999

Observamos el resultado del servidor:

Atendiendo las peticiones…
Pulse Enter para salir…
Constructor.
Metodo: Suma.
Metodo: Potencia.
Metodo: Divide.
Metodo: Divide.

Como podemos ver, solo se llama una vez al constructor, es decir, solo se crea un objeto el cual usarán todos los clientes.

La salida del cliente1:

Suma 2+2 = 4
Potencia 10^5 = 100000
Hemos cambiado la base a 5.0
Pero la base es: 5
Division 8/2 = 4
System.Exception: Division por 0

A diferencia que en SingleCall, una vez que hemos modificado el atributo laBase, este se puede consultar y obtener el último cambio, es decir, se guarda el estado.

Y la salida del cliente2:

LaBase la hemos cambiado desde el primer cliente
Asi que vemos que la base desde el segundo es: 5

Ya que desde el primer cliente cambiamos el atributo laBase, al hacer una consulta desde el segundo, vemos que recogemos el último estado de la calculadora aunque se haya cambiado desde otro cliente.

Vida del objeto

¿Que pasa si dejamos el servidor ejecutándose y pasan 5 minutos (aproximadamente) desde la última llamada de un cliente? Pues que el servidor destruye el objeto. .NET Remoting usa el concepto de vida del objeto para poder destruirlo pasados unos minutos. Prueba a ejecutar el servidor, luego el cliente 1, esperar 5 minutos y ejecutar el cliente 2:

./Servidor.exe 9999

./Cliente.exe localhost 9999

[5 minutos después...]

./Cliente2.exe localhost 9999
LaBase la hemos cambiado desde el primer cliente
Asi que vemos que la base desde el segundo es: 10

El seguimiento de este programa sería:

  1. El servidor crea un nuevo objeto calculadora con el atributo laBase = 10.
  2. El Cliente 1 cambia laBase = 5.
  3. Pasan más o menos cinco minutos, así que el servidor destruye la calculadora.
  4. El Cliente 2 necesita la calculadora, así que el servidor crea un nuevo objeto calculadora con el atributo laBase = 10.
  5. El Cliente 2 usa la calculadora, pero no obtiene el estado que había estado usando el Cliente 1.

Como podemos ver, al pasar un tiempo, el servidor destruye el objeto y el Cliente 2 debe usar un nuevo objeto Calculadora.

Esta forma de destruir los objetos si ningún cliente los utiliza durante un tiempo puede que nos sea de ayuda por temas de la seguridad o de liberación de memoria. Pero si no queremos que el objeto se autodestruya pasado un tiempo, habrá que añadir el siguiente método al código de la clase Calculadora:

  1. public override object InitializeLifetimeService()
  2. {
  3.   // Un truco para que el objeto viva para
  4.   // siempre.
  5.   return null;
  6. }

Sobre la vida de los objetos pasaremos a hablar en otro capítulo, aunque necesitaba remarcarlo por si alguien lo necesita.

Puede que haya ido un poco rápido, esto es así ya que si comprendisteis bien la forma SingleCall, esta forma no os supondría mucha más dificultad. En caso contrario, comentarme vuestras dudas.

Indice general de los manuales

  1. Introducción, instalación en Ubuntu y creación de una calculadora.
  2. Modos de compartición de objetos. Creando nuestra primera calculadora distribuida.
    1. Modos de compartición de objetos: Singlecall.
    2. Modos de compartición de objetos: Singleton.  «  [Leyendo]
    3. Modos de compartición de objetos: CAO.
  3. Canales: TCP y HTTP. Configuración en archivo XML.
  4. Uso de interfaces para separar el código entre cliente y servidor.

© 2007 El blog de ERiDeM. Free wordpress themes.