Posteado por: kmilodenisgonzalez | marzo 15, 2011

Pyro-El RMI de Python

Python remote object

Pyro (Python remote object) es una poderosa Tecnología de Objetos Distribuido escrita en python, su diseño lo hace fácil de usar; Pyro no es más que un midleware de objetos distribuidos con el cual se implementa el patrón cliente – servidor, hay que tener en cuenta que en un sistema de objetos distribuidos este patrón es difícil de ver. La mayoría de las veces todas las partes del sistema cambian los roles, un momento en que un cliente llama a un objeto remoto, otro momento cuando el mismo objeto se llama desde otras partes del sistema. Para un buen entendimiento, es importante ver que en una sola llamada de método hay siempre dos partes diferenciadas del sistema: la parte del cliente que inicia la llamada al método, y la parte del servidor que acepta y ejecuta la llamada. Para ser precisos, hay realmente tres partes: entre el cliente y el servidor esta el middleware de objetos distribuidos, en este caso: Pyro.

Programa Cliente

Esta es la parte del programa que envía pedidos al servidor, para llevar a cabo ciertas acciones. Es el código que realmente utiliza los objetos remotos para llamar a sus métodos.

Los clientes Pyro se parecen a los programas normales de Python. Pero eso es todo el punto de Pyro: este permite crear sistemas de objetos distribuidos con un mínimo esfuerzo. Esto hace que la utilización de objetos remotos sea (casi) transparente. El código de cliente tiene que realizar algunos pasos de inicialización y de instalación. Y porque estamos hablando de objetos remotos aquí, no se puede crear instancias de objetos de la forma habitual. Ellos tienen que utilizar un mecanismo de dos pasos:

1. Encontrar el identificador de la ubicación del objeto requerido. Esto se hace utilizando el nombre de Pyro Server(Servidor de Nombre), vea a continuación.

2. Crear un tipo especial de objeto que llama al objeto remoto. Esto se llama un proxy, ver abajo.

Una vez que tiene este objeto proxy, el cliente puede llamar así, como si se tratara de un objeto -local- de Python.

Programa Servidor

El servidor es el hogar de los objetos que se accede de forma remota. Cada instancia de objeto tiene que ser parte de un programa de Python, así que eso es todo. El servidor tiene que hacer varias cosas:

1. Crea instancias de objetos usando un poco de ingeniería Pyro.

2. Obtener los nombres de las instancias, y registra estos con el servidor de nombre.

3. Decirle a Pyro que tiene que ocuparse de estos casos.

4. Poner a Pyro a reposar en un bucle de espera para las llamadas de los método de entrada.

Configurando Pyro:

Se puede cambiar los ajustes en el código, en tiempo de ejecución. También puede cambiar todos los ajustes antes de comenzar Pyro, y la mayoría de los ajustes se pueden cambiar dinámicamente durante la ejecución también. Tenga en cuenta que usted no puede usar esto para cambiar Pyro.config.PYRO_STORAGE! Véase más adelante!

… Pyro.config.PYRO_PORT = 7000

… Pyro.config.PYRO_TRACELEVEL = 3

Definir las variables de entorno que sobrescriben la configuración por defecto.

Cada tema tiene una configuración equivalente de la variable de entorno. Si defines esta, puedes sobrescribir la configuración por defecto para ese tema. Por ejemplo, podría ser conveniente tener su Programa Pyro generando archivos de registro de programas y ponerlos en un directorio designado de registro:

…$ export PYRO_LOGFILE=/var/log/PYRO/logfile

…$ export PYRO_TRACELEVEL=3

Archivos de configuración


Puede utilizar un archivo de configuración que pueden contener algunos pequeños cambios de configuración o de una nueva configuración para todas las partidas. Pyro comprueba si la variable de entorno PYRO_CONFIG_FILE a cambiado. Si no cambia, o si cambia como una cadena vacía,   Pyro chequea el archivo Pyro.conf en el directorio actual. Si existe, utiliza este como un archivo de configuración. Si no existe, Pyro utiliza el incorporado por defecto en la configuración. Si la variable de entorno se establece, Pyro utiliza el valor como el nombre para el archivo de configuración. Si el archivo de configuración no se puede leer, se produce una excepción PyroError.

El formato del fichero de configuración es muy sencillo. Se trata de un archivo de texto, y cada línea puede estar vacía, comentariada, o con un elemento de configuración. Un comentario comienza con ‘#’. Un elemento de configuración de ajuste es el formato de ‘ITEM = VALOR’. Si Pyro encuentra una configuración desconocida, se produce una excepción KeyError.

Tenga en cuenta que PYRO_CONFIG_FILE es inútil dentro de un archivo de configuración. Después de la inicialización, establece la ruta absoluta del archivo de configuración que se usó (o la cadena vacía, si no se utilizó el archivo de configuración). Tenga en cuenta que el establecimiento de PYRO_CONFIG_FILE dentro de su código es inútil, porque Pyro ya ha sido inicializado en ese punto.

Importante: Variables de entorno sobrescriben la configuración del fichero de configuración, Los cambios en el  fichero sobrescriben las configuraciones construidas por defectos en tiempo de ejecución.

Un cliente y servidor

#!/usr/bin/env python

import Pyro.core
import os,sys

class Servidor(Pyro.core.ObjBase):
	def __init__(self, rootdir):
		Pyro.core.ObjBase.__init__(self)
		self.dirprinc=os.path.abspath(rootdir)
		print "El servidor de fichero esta sirviendo desde ",self.dirprinc

	def listdir(self):
		fichero=[]

		for fich in os.listdir(self.dirprinc):
			if not os.path.isdir(os.path.join(self.dirprinc,fich)):
				fichero.append(fich)
		return fichero

	def recuperarFichero(self, file):
		return open(os.path.join(self.dirprinc,file),'rb').read()

def main():
	dir = raw_input('Entre la direccion absoluta de la carpeta a servir, ej(\'/home/mario/\'):\n')
	if os.path.isdir(dir):
		try:
			Pyro.core.initServer()
			demonio=Pyro.core.Daemon()
			uri=demonio.connect(Servidor(dir), "servidor")
			print "El servidor de fichero esta corriendo.",uri
			demonio.requestLoop()
		except:
			demonio.disconnect(uri.objectID)
	else:
		print ”\n Direccion erronea”
		main()

if __name__=="__main__":
	main()

#!/usr/bin/env python

import Pyro.core
import sys,time

class Cliente(object):
	def __init__(self):
		self.servidor = Pyro.core.getProxyForURI("PYROLOC://localhost:7766/servidor")

	def menu(self):
		print "\nls : listar directorio"
		print "r  : copiar fichero"
		print "q : cerrar"

	def cli(self):
		while True:
			self.menu()
			cmd=raw_input("?>")
			if cmd=="ls":
				self.ls()
			elif cmd.startswith("r "):
				self.recuperarFichero(cmd[2:])
			elif cmd=="q":
				return
			else:
				print "comando no valido"

	def ls(self):
		fichero = self.servidor.listdir()
		fichero.sort()
		for f in fichero:
			print f

	def recuperarFichero(self,fichero):
		print "Recuperando ",fichero," ..."
		tiempoi=time.time()
		try:
			datos=self.servidor.recuperarFichero(fichero)
		except IOError,x:
			print "error: ",x
		else:
			duracion=time.time()-tiempoi
			print len(datos),"bytes recibidos en",int(duracion),"segundos",
			if duracion>0:
				print "=",int(len(datos)/duracion/1024.0),"kb/sec"
			open(fichero,"wb").write(datos)
			print "copiado a",fichero

def main(args):
	Pyro.core.initClient()
	client=Cliente()
	client.cli()

if __name__=="__main__":
	main(sys.argv)

Clase Remota.

Crear un módulo de Python que contiene las clases que desee acceder remotamente. Hay algunas restricciones inducidas por Pyro:

* La clase remoto no puede tener un  método __init__. Tu deberías utilizar un método de inicialización que se debe llamar explícitamente después de vincular el objeto remoto. El método __init__ sólo será llamado en el lado del servidor cuando el objeto es creado.
* La clase remoto no puede tener acceso directo a atributos, a menos que conscientemente decida utilizar un proxy que soporte el acceso a atributo. Véase a continuación. Usted no tiene que utilizar getters y setters para cada uno de las variable miembros.

Si mantiene esto en mente, todo debería ir bien. Puede utilizar todos los tipos de Python y las listas de parámetros y las excepciones en el código. Pyro se ocupará de lo demás muy bien.

Inicialización

Tu deberías inicializar Pyro antes de usarlo en tu Servidor, Esto se hace llamando.

Pyro.core.initServer()

Si el argumento opcional banner = 1, un  mensaje corto se imprime en la salida estándar. También hay un segundo argumento opcional storageCheck. Este por defecto es 1 y Pyro comprobará la disponibilidad de el directorio PYRO_STORAGE. Si se establece en 0, Pyro no realiza comprobación. Si el trace level no es cero, un mensaje de inicio se escribe en el registro. Este mensaje muestra la opciones de configuración activos.

No es estrictamente necesario  llamar a Pyro.core.initServer(), si estás creando un demonio Pyro. Si usted está haciendo que (véase el párrafo siguiente – es muy común que hay que hacer en primer lugar) Pyro se inicialice automáticamente. Si no estás haciendo esto, y estás utilizando otras  funciones de Pyro, entonce no funcionará porque Pyro creerá que eres un cliente, y llama a la función de inicialización mal. Por lo tanto, es mejor llamar a Pyro.core.initServer().

El ejemplo que les mostrare es una versión minimalista de uno presente en el código fuente de Pyro, ajustado para esta publicación. En este ejemplo elimine el uso de Nameserver (servidor de nombre).

Nameserver: A modo generar el servidor de nombre (nameserver) es una funcionalidad que permite a los clientes encontrar el servidor en la red sin tener que especificar la dirección IP del servidor, esto por el momento solo es posible en redes locales; ya que la magia ocurre a través del broadcast. Si desea ver cómo trabaja con el ver la documentación oficial, la mayoría de los ejemplos oficiales estan hechos empleando el nameserver.

Creando un demonio Pyro.

El programa servidor debe crear un objeto demonio Pyro, que contiene toda lógica necesaria para la aceptación de los pedidos y el envío de sus objetos a través de sus métodos.

demonio=Pyro.core.Daemon()

 

De esta forma creamos un demonio para registrar nuestro objeto Pyro que va a ser accedido remotamente (véase a continuación).

uri=demonio.connect(Servidor(dir), "servidor")

Si el demonio no tiene referencia, podría ser (destruido) por el recolector de basura de Python. Incluso si ha conectado objetos Pyro a el demonio. Por lo tanto, usted tiene que asegurarse de mantener una referencia a su objeto demonio en todo momento. Se recomienda de todos modos porque Pyro puede terminar limpiamente su solicitud llamando a demonio.shutdown() cuando se sale. Normalmente esto no es un problema porque el programa crea un demonio, y pide su requestLoop.

demonio.requestLoop()

Con esto le decimos al demonio que se mantenga a la espera de peticiones por parte del cliente, el metodo requestLoop() acepta otros parámetros que podrían ser de utilidad (ver The Daemon handleRequest loop)

Cliente

Inicialización

Antes de usar el cliente debemos inicializarlo, esto se hace llamando a:

Pyro.core.initClient()

Una vez inicializado el Cliente debemos establecer conexión con el servidor a través del uri, fíjense que pongo localhost por que en este caso tanto el servidor como el cliente están en la misma máquina de lo contrario sería el ip del servidor, el puerto y id.

Importante: la uri podrían ser PYRONAME:// o PYROLOC://, la primera es cuando empleamos Name Server(Servidor de Nombre).

class Cliente(object):
	def __init__(self):
		self.servidor = Pyro.core.getProxyForURI("PYROLOC://localhost:7766/servidor")

Una vez lograda la conexión podríamos ya llamar los métodos del servidor como si fueran métodos propios del cliente (véase siguiente ejemplo).


	def recuperarFichero(self,fichero):
		print "Recuperando ",fichero," ..."
		tiempoi=time.time()
		try:
			datos=self.servidor.recuperarFichero(fichero)

Con esto finaliza este ejemplo, aquí ni siquiera se muestra toda la potencialidad de Pyro pero ayuda a iniciarse con esta poderosa tecnología.


descarge Pyro







#!/usr/bin/env python import Pyro.core import os,sys class Servidor(Pyro.core.ObjBase): def __init__(self, rootdir): Pyro.core.ObjBase.__init__(self) self.dirprinc=os.path.abspath(rootdir) print "El servidor de fichero esta sirviendo desde ",self.dirprinc def listdir(self): fichero=[] for fich in os.listdir(self.dirprinc): if not os.path.isdir(os.path.join(self.dirprinc,fich)): fichero.append(fich) return fichero def recuperarFichero(self, file): return open(os.path.join(self.dirprinc,file),'rb').read() def main(): dir = raw_input('Entre la direccion absoluta de la carpeta a servir, ej(\'/home/mario/\'):\n') if os.path.isdir(dir): try: Pyro.core.initServer() demonio=Pyro.core.Daemon() uri=demonio.connect(Servidor(dir), "servidor") print "El servidor de fichero esta corriendo.",uri demonio.requestLoop() except: demonio.disconnect(uri.objectID) else: print ”\n Direccion erronea” main() if __name__=="__main__": main()
 

 

 

 

 

 

Anuncios

Responses

  1. Hello! aabgcga interesting aabgcga site!


Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

Categorías

A %d blogueros les gusta esto: