Está en la página 1de 27

Primeros pasos con ORBacus 4

Diego Sevilla Ruiz


Sistemas Distribuidos, 5o

Indice
1. Introducci
on

2. Descarga y copia

3. Variables de entorno

4. Primeros pasos
4.1. Fichero IDL . .
4.2. Cliente . . . . .
4.3. Implementaci
on
4.4. El servidor . .
4.5. Makefile . . . .
4.6. Ejecucion . . .

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

4
. 4
. 5
. 6
. 8
. 10
. 12

5. Aspectos avanzados: Threads


5.1. Uso de Threads en ORBacus . . . . . . .
5.2. El ejemplo . . . . . . . . . . . . . . . . . .
5.3. Definiciones IDL . . . . . . . . . . . . . .
5.4. El cliente . . . . . . . . . . . . . . . . . .
5.5. La implementaci
on del servidor del sensor
5.6. Makefiles . . . . . . . . . . . . . . . . . .
5.7. Configuracion de Threads en ORBacus . .

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

. .
. .
del
. .
. .
. .

. . . . .
. . . . .
servant
. . . . .
. . . . .
. . . . .

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

6. Revisi
on

1.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

13
13
14
14
15
19
25
26
27

Introducci
on

Este documento explica los primeros pasos para usar ORBacus en su versi
on para
C++. Este software se utilizar
a en las practicas de la asignatura. ORBacus es una
implementaci
on de CORBA de las m
as flexibles y mejor implementadas. Adem
as, aunque

no es gratis, su codigo esta disponible para ser usado en universidades sin cargo. Existen
otros totalmente libres, pero ORBacus ofrece la solucion m
as sencilla y m
as potente a
la vez. Este documento muestra como descargar, compilar y un ejemplo sencillo de uso
con ORBacus.

2.

Descarga y copia

Para realizar las practicas se puede descargar el software ORBacus versi


on 4 de la
direccion:
http://ditec.um.es/ssdd/OB-4.1.0.tar.gz
Y posteriormente descomprimirlo en un directorio que se utilizara para la compilaci
on:
tar zxvf OB-4.1.0.tar.gz
que a su vez crea el directorio OB-4.1.0.
Entrando dentro de ese directorio, hay que realizar dos tareas:
Editar el fichero config/gcc-check y ponerle como segunda lnea:
exit 0
(esto es debido a que el script de comprobacion del compilador gcc no funciona
con las versiones nuevas, 3.x).
Ejecutar el script runconfig:
dsevilla@neuromancer:~/prog/ob/OB-4.1.0$ ./runconfig
************************
* ORBacus Configurator *
************************
Enter c if you use a C shell, or b for a bourne shell:
[b] b
Please select from the following compiler/platform combinations:
(1)
(2)
(3)
(4)
(5)

SUN Forte 6 update 2 C++ 5.3


GCC 2.95.3
SGI C++ 7.2 or 7.3
HP aC++ A.03.27
AIX VisualAge C++ 5.0

SUN Solaris 2.6, 7 and 8


SUN Solaris, Linux
SGI Irix 6.5
HP-UX B.11.00
AIX Version 4.3.x

(6) Compaq C++ 6.2-024

Compaq Tru64 V5.1

Please choose your compiler/platform combination:


[2] 2
Do you want to create shared libraries?
[yes]
Do you want optimized code to be generated?
[no]
Add debug information to the generated code?
[no]
Please enter any extra preprocessor flags, like -I/some/directory:
[]
Please enter any extra compiler flags, like -pipe:
[]
Please enter any extra linker flags, like -L/some/directory:
[]
Please enter any extra archiver flags, like -xarch=v9:
[]
Where do you want to install everything?
[/home/dsevilla/prog/ob]

To run configure, execute the following code in your shell:


. ./go

El directorio de instalaci
on puede ser el que el usuario elija, como por ejemplo
/usr/local. A partir de ahora lo llamaremos $ORBACUS.
Finalmente, debemos ejecutar:
dsevilla@neuromancer:~/prog/ob/OB-4.1.0$ . ./go
Eso ejecuta una serie de comprobaciones necesarias para poder compilar el software.
Finalmente, hay que ejecutar make install min, que construye ORBacus y lo instala

en el directorio $ORBACUS. El proceso de compilaci


on es largo (al menos una hora). En el
caso de tener que interrumpir el proceso, hay que repetir los pasos puestos en la u
ltima
parte: Ejecutar el guion go y despues make install min. El target install min
instala s
olo las partes mnimas necesarias (no ejemplos, demos, tests, etc.). En el caso
de que el proceso fallase, se puede intentar en dos pasos, make y make install.

3.

Variables de entorno

Una vez compilado e instalado ORBacus en el directorio $ORBACUS, se tienen que


establecer las variables de entorno necesarias:
export PATH=$PATH:$ORBACUS/bin
export LD LIBRARY PATH=$LD LIBRARY PATH:$ORBACUS/lib
Es conveniente introducir esas definiciones dentro de un fichero, por ejemplo orbacus-env:
export ORBACUS= (directorio donde ORBacus est
a instalado)
export PATH=$PATH:$ORBACUS/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ORBACUS/lib
y ejecutarlo con:
. orbacus-env
(el punto es equivalente a la orden source del shell).

4.

Primeros pasos

Para comprender el funcionamiento de ORBacus y para introducir las caractersticas


del proceso de desarrollo con el, introduciremos un ejemplo sencillo de una aplicacion
que define un IDL, un cliente y un servidor.

4.1.

Fichero IDL

El fichero IDL, Hola.idl es el siguiente:


1

interface Hola
{
string dihola ( in long num ) ;
};

// $Id : Hola . idl 220 2004 -11 -01 21:10:05 Z dsevilla $

La funcion dihola simplemente retornara un string con la cadena hola concatenada


tantas veces como le indique el par
ametro num.
Para generar los stubs y skeletons, hay que ejecutar el compilador de IDL:

idl Hola.idl
Esto genera los ficheros de stub (Hola.h y Hola.cpp) y skeleton (Hola skel.h y
Hola skel.cpp).

4.2.

Cliente

A continuaci
on se muestra el cliente (cliente.cpp): Es un programa que es capaz de
utilizar el objeto Hola:
2

# include
# include
# include
# include

< OB / CORBA .h >


" Hola . h "
< iostream >
< stdlib .h >

// Incluir las definiciones de ORBacus


// Incluir el " stub "

// argv [1] IOR


// argv [2] n
u mero de veces que dice hola

10

12

14

16

18

20

22

int
main ( int argc , char ** argv )
{
try {
// Iniciar el ORB
CORBA :: ORB_var orb = CORBA :: ORB_init ( argc , argv ) ;
// Recuperar la cadena de caracteres de la l
nea
// de comandos que guarda el IOR y convertirla
// en una referencia a un objeto CORBA
CORBA :: String_var s ;
CORBA :: Object_var o = orb - > string_to_object ( argv [1]) ;
// Obtener el n
u mero de la l
nea de comandos
CORBA :: Long i = atol ( argv [2]) ;

24

26

// Convertir el objeto CORBA a un objeto de la clase


// Hola
Hola_var h = Hola :: _narrow ( o ) ;

28

30

32

34

36

// Llamar al m
e todo dihola usando la referencia al objeto
s = h - > dihola ( i ) ;
std :: cout << s << std :: endl ;
} catch (...)
{
std :: cerr << " quietorl ! " << std :: endl ;
}
}

38

// $Id : cliente . cpp 174 2004 -09 -28 23:33:43 Z dsevilla $

El cliente realiza las siguientes labores:


Lnea 1: Incluye el fichero necesario para los programas CORBA que utilizan ORBacus.

Lnea 2: Incluye el stub para el tipo de objeto Hola.


Lnea 14: Se inicia el ORB. Normalmente, el ORB se implementa como una funcion
de librera. Esta llamada realiza todas las funciones de inicializacion para el ORB.
Lnea 20: Se utiliza la operacion del ORB string to object para convertir el IOR
dado en la lnea de comando como primer par
ametro en una referencia a un objeto
CORBA. Todos los objetos CORBA heredan de la interfaz CORBA::Object.
Lnea 27: El metodo narrow se utiliza para especializar la referencia obtenida
a un objeto del tipo especfico. En este caso Hola. La funcion devolvera en h la
referencia especializada a un objeto de tipo Hola, o un objeto nulo si la conversi
on
no se puede realizar (el objeto en realidad no era del tipo especfico requerido).
Para comprobar si una referencia a un objeto CORBA es nula, se utiliza la funcion
CORBA::is nil.
Lnea 30: Se realiza la llamada propiamente dicha. La abstraccion proporcionada
por CORBA permite hacer una llamada al objeto remoto como si fuera un objeto
local. El resultado se introduce en la variable s.

4.3.

Implementaci
on del servant

Para implementar un objeto CORBA, esto es, para ofrecer sus servicios al mundo, se
tienen que implementar dos cosas:
El servant que contiene la implementaci
on de los metodos del interfaz que se ofrece
al exterior,
y un servidor, que quedar
a esperando conexiones en un puerto IP.
El servant es simplemente un objeto del lenguaje de programaci
on (en este caso C++)
que implementa la funcionalidad de los metodos del objeto CORBA. Este servant es
llamado por el skeleton cuando un cliente llama a un metodo del objeto CORBA implementado por ese servant.
El compilador de IDL de ORBacus ofrece la posibilidad de generar automaticamente
una implementaci
on vaca del servant que podra modificar el programador para implementar las operaciones. Este esqueleto vaco se genera ejecutando:
idl --impl Hola.idl
Esto genera dos ficheros vacos: Hola impl.h y Hola impl.cpp. A continuaci
on se
lista el fichero Hola impl.h:
1

# ifndef ___Hola_impl_h__
# define ___Hola_impl_h__

# include < Hola_skel .h >


5

11

13

//
// IDL : Hola :1.0
//
class Hola_impl : virtual public POA_Hola ,
virtual public PortableServer ::
RefCountServantBase
{
Hola_impl ( const Hola_impl &) ;
void operator =( const Hola_impl &) ;
PortableServer :: POA_var poa_ ;

15

17

public :
Hola_impl ( PortableServer :: POA_ptr ) ;
~ Hola_impl () ;

19

21

virtual PortableServer :: POA_ptr _default_POA () ;


23

//
// IDL : Hola / dihola :1.0
//
virtual char * dihola ( CORBA :: Long num )
throw ( CORBA :: SystemException ) ;

25

27

29

};

31

# endif

33

// $Id : Hola_impl . h 174 2004 -09 -28 23:33:43 Z dsevilla $

De destacar en este fichero es:


El servant se implementa en una clase Hola impl. Todas las clases servant heredan
de la clase POA <interfaz>.
El interfaz de ese objeto, salvo algunos metodos adicionales que se explican en la
teora de la asignatura, sigue el definido en el IDL, con la operacion dihola.
El codigo del servant es el que se muestra a continuaci
on. Se ha implementado la
funcion dihola con una implementaci
on trivial en el fichero Hola impl.cpp:
1

# include < OB / CORBA .h >


# include < Hola_impl .h >

//
// IDL : Hola :1.0
//
Hola_impl :: Hola_impl ( PortableServer :: POA_ptr poa )
: poa_ ( PortableServer :: POA :: _duplicate ( poa ) )
{
}

11

Hola_impl ::~ Hola_impl ()

13

{
}

15

17

19

PortableServer :: POA_ptr
Hola_impl :: _default_POA ()
{
return PortableServer :: POA :: _duplicate ( poa_ ) ;
}

21

23

25

27

29

//
// IDL : Hola / dihola :1.0
//
char *
Hola_impl :: dihola ( CORBA :: Long num )
throw ( CORBA :: SystemException )
{
char * _r = CORBA :: string_alloc (4 * num + 1) ;
for ( size_t i = 0; i < num ; ++ i )
strcpy ( _r + 4* i , " Hola " ) ;

31

33

return _r ;
35

37

// $Id : Hola_impl . cpp 174 2004 -09 -28 23:33:43 Z dsevilla $

4.4.

El servidor

En cualquier aplicacion CORBA debe existir un servidor que quede esperando las
peticiones sobre los objetos CORBA implementados por el (servants). El servidor es un
programa C++ normal que dejara activado un servant para el objeto CORBA.
1

# include < OB / CORBA .h >

# include " Hola_impl . h "

# include < cstdlib >


# include < fstream >

using namespace std ;


9

11

13

int
main ( int argc , char * argv [] , char *[])
{
CORBA :: ORB_var orb ;

15

17

try
{
orb = CORBA :: ORB_init ( argc , argv ) ;

19

//

// Obtener el POA ra
z
//
CORBA :: Object_var poaObj = orb - > r e s o l v e _ i n i t i a l _ r e f e r en c e s ( "
RootPOA " ) ;
PortableServer :: POA_var rootPOA = PortableServer :: POA :: _narrow
( poaObj ) ;

21

23

25

//
// Obtener el POA manager
//
PortableServer :: POAManager_var manager = rootPOA - >
the_POAManager () ;

27

29

//
// Crear el objeto implementaci
on
//
Hola_impl * hImpl = new Hola_impl ( rootPOA ) ;
CORBA :: Object_var o = rootPOA - > s e r v a n t _ t o _ r e f e r e n c e ( hImpl ) ;
Hola_var hola = Hola :: _narrow ( o ) ;

31

33

35

37

//
// Grabar la referencia en un fichero
//
CORBA :: String_var s = orb - > object_to_string ( hola ) ;

39

41

const char * refFile = " Hola . ref " ;


ofstream out ( refFile ) ;
if ( out . fail () )
{
cerr << argv [0] << " : no puedo abrir " << refFile << endl ;
return 1;
}

43

45

47

49

out << s << endl ;


out . close () ;

51

53

//
// Ejecutar la implementaci
on
//
manager - > activate () ;
orb - > run () ;

55

57

59

return 0;
}
catch ( const CORBA :: Exception & ex )
{
cerr << ex << endl ;
return 1;
}

61

63

65

67

69

// $Id : servidor . cpp 174 2004 -09 -28 23:33:43 Z dsevilla $

El servidor contiene casi toda la carga de la dificultad de la programaci


on con CORBA.
Las tareas que implementa el servidor son las siguientes:
Lnea 18: El ORB se inicia como en el cliente.
Lneas 2324: Se obtiene el POA raz. El objeto servidor se tiene que registrar en
un adaptador de objetos (OA). En CORBA, el POA es el adaptador de objetos,
que se puede configurar como una jerarqua. En este caso, registraremos el objeto
en el POA raz (RootPOA). Para la mayora de los usos, este adaptador de objetos
es suficiente.
Lnea 19: Se obtiene el POA Manager. Este manager controla a un conjunto de
adaptadores de objetos, permitiendoles funcionar, o bien encolar las peticiones o
rechazarlas.
Lnea 34: Se crea un objeto servant Hola impl.
Lnea 35: Se utiliza el metodo servant to reference del POA para obtener una
referencia CORBA a partir de un servant.
Lnea 36: La referencia se convierte a una referencia de un interfaz Hola. Este paso
no es necesario, se muestra por completitud.
Lnea 41: La referencia se convierte en una cadena de caracteres con la funcion del
ORB object to string.
Lneas 4352: La referencia en formato cadena de caracteres se escribe al fichero
Hola.ref.
Lnea 57: Se activa el manager del POA. Desde ese momento, todos los objetos
registrados en ese POA puede recibir invocaciones de metodos.
Lnea 58: El ORB se pone a funcionar (esperar peticiones). El programa queda
as esperando las peticiones de los clientes.

4.5.

Makefile

Es importante construir un buen fichero Makefile, debido a que se tienen que utilizar
varios programas y generar varios ficheros, por lo que el fichero para el programa make no
es trivial. A continuaci
on se muestra un fichero Makefile para el ejemplo que estamos
considerando:
1

# Makefile
#
# Suponemos que la variable ORBACUS est
a definida en el entorno , y
que
# el compilador de IDL est
a dentro de los directorios listados en
la variable
# $PATH . Si no , otra alternativa ser
a utilizar $ORBACUS / bin / idl

10

#
CPPFLAGS = - I$ ( ORBACUS ) / include -I .
LDFLAGS = - L$ ( ORBACUS ) / lib
LIBS = - lOB - lJTC - lpthread - ldl

15

IDLFILE = Hola . idl


GENFILES = $ ( patsubst %.idl , % _skel .h , $ ( IDLFILE ) ) \
$ ( patsubst %.idl , % _skel . cpp , $ ( IDLFILE ) ) \
$ ( patsubst %.idl , %.h , $ ( IDLFILE ) ) \
$ ( patsubst %.idl , %. cpp , $ ( IDLFILE ) )

17

all : cliente servidor

19

$ ( GENFILES ) : $ ( IDLFILE )

21

cliente : cliente . o Hola . o


$ ( CXX ) -o $@ $ ( LDFLAGS ) $ ( LIBS ) $ ^

11

13

23

25

servidor : servidor . o Hola_skel . o Hola . o Hola_impl . o


$ ( CXX ) -o $@ $ ( LDFLAGS ) $ ( LIBS ) $ ^

27

# Parte gen
e rica

29

%_skel . h %_skel . cpp %.h %.cpp : %.idl


idl $ <

31

33

35

clean :
rm - rf cliente servidor $ ( GENFILES ) *. o core *~ . depend
. depend :
$ ( CPP ) $ ( CPPFLAGS ) - MM - MG *. cpp 2 >/ dev / null > $@

37

- include . depend
39

# $Id : Makefile 174 2004 -09 -28 23:33:43 Z dsevilla $

Las libreras utilizadas son parte del ORB (OB y JTC), adem
as de las libreras necesarias
para ese ORB en Linux (-lpthread, -ldl).
La ejecuci
on de make genera una salida como la siguiente:
$ make
gcc -E -I/opt2/corbalc/orbs/orbacus/include -I. -MM -MG *.cpp > .depend
idl Hola.idl
g++ -I/opt2/corbalc/orbs/orbacus/include -I. -c -o cliente.o cliente.cpp
g++ -I/opt2/corbalc/orbs/orbacus/include -I. -c -o Hola.o Hola.cpp
g++ -o cliente -L/opt2/corbalc/orbs/orbacus/lib -lOB -lJTC -lpthread
-ldl cliente.o Hola.o
g++ -I/opt2/corbalc/orbs/orbacus/include -I. -c -o servidor.o servidor.cpp
g++ -I/opt2/corbalc/orbs/orbacus/include -I. -c -o Hola_skel.o Hola_skel.cpp
g++ -I/opt2/corbalc/orbs/orbacus/include -I. -c -o Hola_impl.o Hola_impl.cpp
g++ -o servidor -L/opt2/corbalc/orbs/orbacus/lib -lOB -lJTC -lpthread

11

-ldl servidor.o Hola_skel.o Hola.o Hola_impl.o

4.6.

Ejecuci
on

La ejecuci
on de la aplicacion necesita primero de la ejecuci
on del servidor. Tal y como
se ha visto, el servidor crea un fichero llamado Hola.ref, en el que introduce el IOR del
objeto servidor. En principio ejecutaremos el cliente y el servidor en la misma m
aquina,
aunque usando el IOR, que se puede transmitir por correo o por cualquier otro medio,
el cliente podra utilizar nuestro objeto servidor desde cualquier otro ordenador. La
ejecuci
on1 :
$ ./servidor &
Esto crea el fichero Hola.ref:
IOR:01dc05080d00000049444c3a486f6c613a312e30003d6040010000000000000
078000000010102000a0000006c6f63616c686f7374003b8525000000abacab3131
303636373432323731005f526f6f74504f410000cafebabe3f9531ff00000000000
00001000000010000002c0000000116000001000100040000002000010009010100
000101000100010509010100020000000001010001000105
Como curiosidad, el programa iordump (tambien perteneciente a ORBacus), permite
obtener los datos del IOR:
$ iordump cat Hola.ref
IOR #1:
byteorder: little endian
type_id: IDL:Hola:1.0
Profile #1: iiop
iiop_version: 1.2
host: localhost
port: 34107
object_key: (37)
171 172 171 49 49 48 54 54 "...11066"
55 52 50 50 55 49
0 95 "742271._"
82 111 111 116 80 79 65
0 "RootPOA."
0 202 254 186 190 63 149 49 ".....?.1"
255
0
0
0
0
"....."
Native char code set:
"ISO 8859-1:1987; Latin Alphabet No. 1"
Char conversion code sets:
"ISO 646:1991 IRV (International Reference Version)"
"ISO/IEC 10646-1:1993; UTF-16, UCS Transformation Format 16-bit form"
1

En el caso de que el ordenador no tenga bien configurada la red, se puede utilizar el comando de
ejecuci
on ./servidor -OAhost localhost & (la opci
on -OAhost especifica la IP a utilizar).

12

"ISO/IEC 10646-1:1993; UCS-2, Level 1"


"X/Open UTF-8; UCS Transformation Format 8 (UTF-8)"
Native wchar code set:
"ISO/IEC 10646-1:1993; UTF-16, UCS Transformation Format 16-bit form"
Wchar conversion code sets:
"ISO/IEC 10646-1:1993; UCS-2, Level 1"
"X/Open UTF-8; UCS Transformation Format 8 (UTF-8)"
Finalmente, el cliente se puede ejecutar recibiendo como primer par
ametro el IOR al
que conectar y como segundo el n
umero de veces que se concatenar
a la palabra Hola:
$ ./cliente cat Hola.ref 6
HolaHolaHolaHolaHolaHola

5.
5.1.

Aspectos avanzados: Threads


Uso de Threads en ORBacus

ORBacus incluye una librera de threads llamada JTC (Java-Threads for C++). Su
uso es muy similar a los hilos de Java. As, al crear una clase C++ se le puede especificar
que es un thread:
# include < JTC / JTC .h >
2

class Hilo : public JTCThread


{
void run () ;
};

Para el manejo automatico de la memoria asociada a un hilo, tambien existe la clase


JTCThreadHandle:
2

JTCThreadHandle h = new Hilo () ;


h - > start () ;

Los threads tambien ofrecen las operaciones isAlive() y terminate(), para comprobar si el hilo se esta ejecutando y para terminarlo en su caso.
Los hilos se pueden convertir en monitores para permitir que se bloqueen y para
permitir hacer secciones crticas:
2

10

class Hilo : public JTCThread , public JTCMonitor {


public :
// M
e todo sincronizado
void m
e todo ()
{
JTCSynchronized s (* this ) ;
}
// M
e todo con una regi
o n sincronizada
void m
e todo2 ()
{

13

// otras cosas ...


{
JTCSyncrhonized s (* this ) ;
// Regi
o n sincronizada
}

12

14

16

};

El metodo ((m
etodo)) es una secci
on crtica. Nadie podra ejecutarlo si ya se esta ejecutando. Las clases JTCSynchronized siguen el patron ((reserva de recursos en creaci
on)),
as que cuando sale de
ambito la variable se elimina el lock sobre el candado.
Vease tambien Henning & Vinoski, cap. 21, aunque ah utilizan ACE (Adaptative
Communication Envionment, Schmidt et al., http://www.cs.wustl.edu/~schmidt).

5.2.

El ejemplo

El siguiente ejemplo muestra el uso de threads en la implementaci


on de una aplicacion
distribuida con m
ultiples clientes. El ejemplo muestra un programa servidor que esta conectado a un ((sensor)). El sensor emite valores peri
odicamente o cuando las condiciones
del medio cambian. Los clientes se suscriben a los eventos que emiten el sensor.
El ejemplo es interesante porque se puede dar que se conecten virtualmente muchos
clientes para leer los datos. El programa no puede tardar mucho tiempo en informar
a los clientes, ya que los eventos del sensor pueden ser muy proximos en el tiempo (es
decir, tiene que ser escalable con respecto al n
umero de clientes).
En la implementaci
on se utilizaran threads, una para cada cliente. Sin embargo, se
pueden utilizar otras alternativas que veremos en la teora, como un ((pool)) de treads,
etc.

5.3.

Definiciones IDL

Las definiciones IDL son basicas. Primero las estructuras comunes. Muestran los datos
que genera el sensor y que se transmiten entre los clientes suscritos y el servidor (fichero
SensorData.idl):
1

# ifndef SENSOR_DATA
# define SENSOR_DATA

struct SensorData
{
long windspeed ;
long other ;
};

# endif
11

// $Id : SensorData . idl 220 2004 -11 -01 21:10:05 Z dsevilla $

El interfaz del sensor es sencillo: permite a


nadir y eliminar ((listeners)) que recibiran
los datos, y un metodo para poner a funcionar el sensor:

14

# include " SensorData . idl "


# include " SensorListener . idl "
interface Sensor
{
void addListener ( in SensorListener listener ) ;
void removeListener ( in SensorListener listener ) ;

// Run sensor
void run () ;

10

};
12

// $Id : Sensor . idl 220 2004 -11 -01 21:10:05 Z dsevilla $


1

# include " SensorData . idl "

interface SensorListener
{
oneway void nueva_lectura ( in SensorData v ) ;
};

// $Id : SensorListener . idl 233 2004 -11 -08 18:22:40 Z dsevilla $

Este u
ltimo fichero define el listener. Como se ve, la funcion de notificaci
on es ((oneway)).
Este dise
no suele ser el usual en aplicaciones de este tipo. Sin embargo, si se quiere asegurar que no se pierden mensajes, el metodo de notificaci
on podra ser un metodo normal,
no oneway.

5.4.

El cliente

Como se ha dicho, en este caso, tanto el cliente como el servidor deben esperar peticiones: el servidor peticiones de a
nadir listeners; el cliente informaciones del sensor a traves
del metodo nueva lectura. As, el cliente debe implementar el objeto SensorListener
para que el servidor pueda informarle de cambios en sl sensor. La implementaci
on no
tiene grandes problemas y es sencilla:
2

# ifndef _ _ _ S e n s o r L i s t e n e r _ i m p l _ h _ _
# define _ _ _ S e n s o r L i s t e n e r _ i m p l _ h _ _

# include < SensorListener_skel .h >

//
// IDL : SensorListener :1.0
//
class SensorListener_impl : virtual public POA_SensorListener ,
virtual public PortableServer ::
RefCountServantBase
{
SensorListener_impl ( const SensorListener_impl &) ;
void operator =( const SensorListener_impl &) ;

10

12

14

15

PortableServer :: POA_var poa_ ;


16

CORBA :: ULong id_ ;


18

public :
20

22

SensorListener_impl ( PortableServer :: POA_ptr , CORBA :: ULong


id ) ;
~ SensorListener_impl () ;

24

virtual PortableServer :: POA_ptr _default_POA () ;

26

//
// IDL : SensorListener / nueva_lectura :1.0
//
virtual void nueva_lectura ( const SensorData & v )
throw ( CORBA :: SystemException ) ;

28

30

};
32

# endif
1

11

# include < OB / CORBA .h >


# include < SensorListener_impl .h >
# include < iostream >
//
// IDL : SensorListener :1.0
//
SensorListener_impl :: SensorListener_impl ( PortableServer :: POA_ptr
poa ,
CORBA :: ULong id )
: poa_ ( PortableServer :: POA :: _duplicate ( poa ) ) , id_ ( id )
{
}

13

15

SensorListener_impl ::~ SensorListener_impl ()


{
}

17

19

21

PortableServer :: POA_ptr
SensorListener_impl :: _default_POA ()
{
return PortableServer :: POA :: _duplicate ( poa_ ) ;
}

23

25

27

29

31

//
// IDL : SensorListener / nueva_lectura :1.0
//
void
SensorListener_impl :: nueva_lectura ( const SensorData & v )
throw ( CORBA :: SystemException )
{
std :: cerr << " Recibido evento ( " << id_
<< " ) . windspeed = " << v . windspeed

16

<< " other = " << v . other


<< std :: endl ;

33

35

37

// $Id : SensorListener_impl . cpp 174 2004 -09 -28 23:33:43 Z dsevilla


$

El metodo nueva lectura, cuando es llamado por el servidor, imprime los valores en
la salida estandar.
1

// -* - mode : c ++; c - basic - offset : 8; -* # include < OB / CORBA .h > // Incluir las definiciones de ORBacus
# include " SensorListener . h "
// Incluir el " stub "
# include " Sensor . h "
# include " SensorData . h "
# include " SensorListener_impl . h "
# include < iostream >
# include < stdlib .h >
# include < vector >

11

const int NUM_LISTENERS =1000;

13

// argv [1] IOR

15

typedef std :: vector < SensorListener_impl * > ImplVector ;


typedef std :: vector < SensorListener_var > PtrVector ;

17

19

21

23

25

int
main ( int argc , char ** argv )
{
try {
ImplVector iv ( NUM_LISTENERS ) ;
PtrVector pv ( NUM_LISTENERS ) ;
// Iniciar el ORB
CORBA :: ORB_var orb = CORBA :: ORB_init ( argc , argv ) ;

27

29

31

33

//
// Obtener el POA ra
z
//
CORBA :: Object_var poaObj =
orb -> r e s o l v e _ i n i t i a l _ r e f e r e n c e s ( " RootPOA " ) ;
PortableServer :: POA_var rootPOA =
PortableServer :: POA :: _narrow ( poaObj ) ;

35

37

39

//
// Obtener el POA manager
//
PortableServer :: POAManager_var manager =
rootPOA -> the_POAManager () ;

41

43

//
// Ejecutar la implementaci
on
//

17

45

manager -> activate () ;

47

// Recuperar la cadena de caracteres de la l


nea
// de comandos que guarda el IOR y convertirla
// en una referencia a un objeto CORBA
CORBA :: Object_var o = orb - > string_to_object ( argv [1]) ;

49

51

53

// Convertir el objeto CORBA a un objeto de la clase


// SensorListener
Sensor_var s = Sensor :: _narrow ( o ) ;

55

57

59

61

63

65

67

//
// Crear mil objetos listener
//
for ( CORBA :: ULong i = 0; i < NUM_LISTENERS ; i ++)
{
SensorListener_impl * hImpl =
new SensorListener_impl ( rootPOA , i ) ;
CORBA :: Object_var o =
rootPOA -> s e r v a n t _ t o _ r e f e r e n c e ( hImpl ) ;
SensorListener_var listener =
SensorListener :: _narrow ( o ) ;
iv [ i ] = hImpl ;
pv [ i ] = listener ;

69

// A~
n adir el listener al sensor
s - > addListener ( listener . in () ) ;

71

}
73

75

s - > run () ;

77

orb -> run () ;

79

for ( CORBA :: ULong i = 0; i < NUM_LISTENERS ; i ++)


{
// Eliminar de la lista del sensor
s - > removeListener ( pv [ i ]) ;

81

83

85

87

89

// Desactivar los objetos del POA


PortableServer :: ObjectId_var oid =
rootPOA - > reference_to_id ( pv [ i ]) ;
rootPOA -> deactivate_object ( oid . in () ) ;
// Eliminar las referencias
// CORBA :: release ( pv [ i ]) ;

91

93

95

97

// Eliminar los servants


delete iv [ i ];
}
} catch (...)
{
std :: cerr << " quietorl ! " << std :: endl ;
}

18

99

// $Id : cliente . cpp 233 2004 -11 -08 18:22:40 Z dsevilla $

101

El cliente es algo m
as complejo. B
asicamente:
1. Crea 1000 listeners.
2. Los registra con el sensor (lneas 5972).
3. Inicia el sensor (lnea 75).
4. Desregistra y desactiva los listeners (lneas 7994).
Para ello, mantiene dos listas: iv, que guarda un array de servants y pv, que guarda
un array de punteros a objetos CORBA (los listeners).

5.5.

La implementaci
on del servidor del sensor

Empecemos con la definicion del fichero de cabeceras C++ del sensor (Sensor impl.h):
1

# ifndef ___Sensor_impl_h__
# define ___Sensor_impl_h__

# include < SensorListener_impl .h >


5

# include < Sensor_skel .h >


7

# include < list >


9

typedef std :: list < SensorListener_ptr > ListenerList ;


11

13

15

17

19

//
// IDL : Sensor :1.0
//
class Sensor_impl : virtual public POA_Sensor ,
virtual public PortableServer ::
RefCountServantBase
{
Sensor_impl ( const Sensor_impl &) ;
void operator =( const Sensor_impl &) ;

21

PortableServer :: POA_var poa_ ;

23

ListenerList ll_ ;

25

27

public :
Sensor_impl ( PortableServer :: POA_ptr ) ;
~ Sensor_impl () ;

29

virtual PortableServer :: POA_ptr _default_POA () ;


31

19

//
// IDL : Sensor / addListener :1.0
//
virtual void addListener ( SensorListener_ptr listener )
throw ( CORBA :: SystemException ) ;

33

35

37

//
// IDL : Sensor / removeListener :1.0
//
virtual void removeListener ( SensorListener_ptr listener )
throw ( CORBA :: SystemException ) ;

39

41

43

//
// IDL : Sensor / run :1.0
//
virtual void run ()
throw ( CORBA :: SystemException ) ;

45

47

49

};

51

# endif

El fichero de implementaci
on del servant es algo m
as complicado. Se muestra a continuaci
on (despues del listado se explica detalladamente):
1

# include < OB / CORBA .h >


# include < Sensor_impl .h >

# include < iostream >


# include < JTC / JTC .h >

11

// Clase - thread que env


a un evento a un listener
class ListenerNotifier : public JTCThread
{
SensorListener_ptr sl_ ;
SensorData d_ ;

13

public :

ListenerNotifier ( SensorListener_ptr sl , const SensorData &


d)
: sl_ ( sl ) , d_ ( d )
{
}

15

17

// M
e todo run del thread
void run ()
{
sl_ - > nueva_lectura ( d_ ) ;
}

19

21

23

};
25

27

29

// Clase sin estado que gestiona el env


o
class L i s t e n e r G r o u p N o t i f i e r
{
typedef std :: list < JTCThreadHandle > ThreadList ;

20

ThreadList tl_ ;
31

public :
void notify ( const ListenerList & ll , const SensorData & d )
{
for ( ListenerList :: const_iterator it = ll . begin () ,
end = ll . end () ;
it != end ; it ++)
{
JTCThreadHandle ln = new ListenerNotifier
(* it , d ) ;
ln -> start () ;

33

35

37

39

41

tl_ . push_back ( ln ) ;
43

45

// Sincronizaci
o n final . Se utiliza el m
e todo "
join "
// para esperar a que terminen los threads .
for ( ThreadList :: const_iterator it = tl_ . begin () ,
end = tl_ . end () ;
it != end ; it ++)
{
do
{
try {
(* it ) -> join () ;
} catch ( const
J T C I n t e r r u p t e d E x c e p t i o n &)
{
}
} while ((* it ) -> isAlive () ) ;
}

47

49

51

53

55

57

59

}
61

};

63

65

67

69

//
// IDL : Sensor :1.0
//
Sensor_impl :: Sensor_impl ( PortableServer :: POA_ptr poa )
: poa_ ( PortableServer :: POA :: _duplicate ( poa ) )
{
}

71

73

75

77

79

Sensor_impl ::~ Sensor_impl ()


{
// Eliminar todos los listeners
for ( ListenerList :: iterator it = ll_ . begin () , end = ll_ .
end () ;
it != end ; it ++)
{
CORBA :: release (* it ) ;
ll_ . erase ( it ) ;

21

}
81

83

PortableServer :: POA_ptr
Sensor_impl :: _default_POA ()
{
return PortableServer :: POA :: _duplicate ( poa_ ) ;
}

85

87

89

91

93

95

97

//
// IDL : Sensor / addListener :1.0
//
void
Sensor_impl :: addListener ( SensorListener_ptr listener )
throw ( CORBA :: SystemException )
{
// TODO : Comprobar duplicados
ll_ . push_back ( SensorListener :: _duplicate ( listener ) ) ;
}

99

101

103

105

107

109

111

113

115

117

119

121

123

125

127

//
// IDL : Sensor / removeListener :1.0
//
void
Sensor_impl :: removeListener ( SensorListener_ptr listener )
throw ( CORBA :: SystemException )
{
// OJO : Este c
o digo no es seguro , por los problemas de
identidad
// en CORBA .
for ( ListenerList :: iterator it = ll_ . begin () , end = ll_ .
end () ;
it != end ; it ++)
{
if ( listener - > _is_equivalent (* it ) )
{
CORBA :: release (* it ) ;
ll_ . erase ( it ) ;
break ;
}
}
}
//
// IDL : Sensor / run :1.0
//
void
Sensor_impl :: run ()
throw ( CORBA :: SystemException )
{
std :: cerr << " Servidor : comenzando " << std :: endl ;

129

131

SensorData * d = new SensorData ;


d - > windspeed = 10;

22

d - > other = 20;


133

135

L i s t e n e r G r o u p N o t i f i e r lgn ;
lgn . notify ( ll_ , * d ) ;

137

delete d ;
std :: cerr << " Servidor : finalizado " << std :: endl ;

139

}
141

// $Id : Sensor_impl . cpp 1744 2007 -03 -15 20:37:01 Z dsevilla $

La implementaci
on del sensor crea un hilo para notificar a cada listener. N
otese que
el crear tantos hilos como elementos a notificar es un riesgo, por lo que se tendran que
idear otras tecnicas, como un conjunto de hilos fijo, etc. Esto se deja como ejercicio.
La clase que implementa ese hilo es ListenerNotifier (lnea 8). ORBacus utiliza
la librera JTC (Java-Threads for C++). As, los hilos son parecidos a los de Java:
heredan de JTCThread y tiene un metodo run. Cada clase ListenerNotifier tiene un
SensorListener al que enva los datos del sensor.
La clase ListenerGroupNotifier es una abstraccion para una comunicaci
on de grupo.
Crea todos los hilos, creando cada uno de los objetos ListenerNotifier (hilos). Cada
uno de los hilos se inicia con start (lnea 40), y se almacenan en una lista de hilos (tl ).
Esta lista guarda objetos de tipo JTCThreadHandle. Estos objetos son handlers para
los hilos que manejan la memoria de los mismos (no hace falta destruirlos, se destruyen
automaticamente al salir de
ambito, como el idiom de adquisicion de recurso en creaci
on).
El siguiente bucle (lneas 4759), utiliza la funcion join para esperar a que todos los
hilos terminen.
Las funciones addListener y removeListener no tienen mucho problema. Su implementaci
on es normal.
Por u
ltimo, el metodo run enva un evento de datos al grupo de los listeners utilizando
la clase ListenerGroupNotifier.
En cuanto al servidor, simplemente crea y activa el objeto Sensor:
# include < OB / CORBA .h >
2

# include " Sensor_impl . h "


4

# include < stdlib .h >


# include < fstream >

using namespace std ;

10

12

int
main ( int argc , char * argv [] , char *[])
{
CORBA :: ORB_var orb ;

14

16

try
{
orb = CORBA :: ORB_init ( argc , argv ) ;

23

18

//
// Obtener el POA ra
z
//
CORBA :: Object_var poaObj = orb -> r e s o l v e _ i n i t i a l _ r e f e r en c e s ( "
RootPOA " ) ;
PortableServer :: POA_var rootPOA = PortableServer :: POA :: _narrow
( poaObj ) ;

20

22

24

//
// Obtener el POA manager
//
PortableServer :: POAManager_var manager = rootPOA ->
the_POAManager () ;

26

28

//
// Crear el objeto implementaci
on
//
Sensor_impl * hImpl = new Sensor_impl ( rootPOA ) ;
CORBA :: Object_var o = rootPOA -> s e r v a n t _ t o _ r e f e r e n c e ( hImpl ) ;
Sensor_var sensor = Sensor :: _narrow ( o ) ;

30

32

34

36

//
// Grabar la referencia en un fichero
//
CORBA :: String_var s = orb -> object_to_string ( sensor ) ;

38

40

const char * refFile = " Sensor . ref " ;


ofstream out ( refFile ) ;
if ( out . fail () )
{
cerr << argv [0] << " : no puedo abrir " << refFile <<
endl ;
return 1;
}

42

44

46

48

out << s << endl ;


out . close () ;

50

52

//
// Ejecutar la implementaci
on
//
manager -> activate () ;
orb -> run () ;

54

56

58

return 0;
}
catch ( const CORBA :: Exception & ex )
{
cerr << ex << endl ;
return 1;
}

60

62

64

66

24

68

5.6.

// $Id : servidor . cpp 174 2004 -09 -28 23:33:43 Z dsevilla $

Makefiles

Por u
ltimo, veamos los ficheros make. Estos ejemplos de makefiles son algo m
as sofisticados que los anteriores. Primero, el fichero Make.rules guarda las reglas generales
para los ficheros IDL. Los dos macros, idlrule y process idls, generan las reglas (en
tiempo de ejecuci
on) para cada fichero IDL a partir de la variable $(IDLFILES):
# -* - Makefile -* - vim : set ft = make :
2

10

12

14

# Para cada fichero IDL , genera una regla de compilaci


on
define idlrule
$ (1) _skel . h $ (1) _skel . cpp $ (1) . h $ (1) . cpp : $ (1) . idl
idl $$ <
CLEANFILES += $ (1) _skel . h $ (1) _skel . cpp $ (1) . h $ (1) . cpp
GENFILES += $ ( CLEANFILES )
endef
# Procesa un conjunto de ficheros IDL en la variable IDLFILES
define process_idls
$ ( foreach i , $ (1) , $ ( eval $ ( call idlrule , $ ( i ) ) ) )
endef

16

$ ( call process_idls , $ ( IDLFILES ) )


18

20

clean :
rm - rf $ ( CLEANFILES )

22

# $Id : Make . rules 234 2004 -11 -09 00:07:51 Z dsevilla $

El resto de Makefile incluye a este fichero, y describe las reglas para compilar cliente
y servidor.

10

# Makefile
#
# Suponemos que la variable ORBACUS est
a definida en el entorno , y
que
# el compilador de IDL est
a dentro de los directorios listados en
la variable
# $PATH . Si no , otra alternativa ser
a utilizar $ORBACUS / bin / idl
#
DEBUG = - g
CPPFLAGS = - I$ ( ORBACUS ) / include -I . $ ( DEBUG )
LDFLAGS = - L$ ( ORBACUS ) / lib
LIBS = - lOB - lJTC - lpthread - ldl

12

IDLFILES = Sensor SensorListener SensorData

14

all : cliente servidor

25

16

include Make . rules

18

CLEANFILES +=*~ *. o cliente servidor . depend core Sensor . ref

20

cliente : cliente . o Sensor . o \


SensorData_skel . o SensorData . o SensorListener_impl . o \
SensorListener . o SensorListener_skel . o
$ ( CXX ) -o $@ $ ( LDFLAGS ) $ ( LIBS ) $ ^

22

24

servidor : servidor . o Sensor_skel . o SensorData . o \


SensorData_skel . o Sensor . o Sensor_impl . o SensorListener . o
$ ( CXX ) -o $@ $ ( LDFLAGS ) $ ( LIBS ) $ ^

26

28

# Parte gen
e rica
30

32

. depend :
$ ( CPP ) $ ( CPPFLAGS ) - MM - MG *. cpp 2 >/ dev / null > $@

34

- include . depend

36

# $Id : Makefile 174 2004 -09 -28 23:33:43 Z dsevilla $

5.7.

Configuraci
on de Threads en ORBacus

ORBacus permite la configuraci


on de las caractersticas de los threads para cada aplicacion. Adem
as, se puede hacer de dos modos: a traves de la lnea de ordenes o a traves
de un API propietario de ORBacus. En cuanto a la lnea de ordenes, se pueden especificar
varios par
ametros:
Modo de funcionamiento del ORB: -ORBreactive (sin threads), -ORBthreaded
(con threads).
Modo de funcionamiento del adaptador de objetos (OA):
-OAreactive, -OAthreaded: modos basicos.
-OAthread per client, -OAthread per request, OAthread pool n
Se pueden especificar en cualquier aplicacion.
En cuanto al API propietario, en la inicializacion del ORB se puede escribir algo como
esto:
OB::Properties_var dflt = OB::Properties::getDefaultProperties();
OB::Properties_var props = new OB::Properties(dflt);
props->setProperty("ooc.orb.conc_model", "threaded");
props->setProperty("ooc.orb.oa.conc_model", "thread_pool");
props->setProperty("ooc.orb.oa.thread_pool", "5");
CORBA::ORB_var orb = OBCORBA::ORB_init(argc, argv, props);
Este codigo establece el modo ((Thread Pool)) con un tama
no de 5 hilos.

26

6.

Revisi
on

$Id: orbacus.tex 3144 2009-10-14 19:22:21Z dsevilla $

27

También podría gustarte