You are on page 1of 9

Reporte de proyecto 1

Sistemas distribuidos
Instituto Politcnico Nacional
Unidad Profesional Interdisciplinaria de Ingeniera y Tecnologas
Avanzadas
Ingeniera Telemtica
14 de Mayo 2015

Pablo Camacho Aguilar


Daniel Sarabia Tiznado
David Azaraf Vargas Baza
Rafael Vicencio Hernndez
2TM7

Objetivo de la prctica
Se tiene una red compuesta de 4 servidores, donde cada servidor sabe hacer tres tareas diferentes , cada
tarea es una operacin matemtica o la simulacin de un algoritmo de computacin (puede
simplemente imprimir un mensaje que indique que ha realizado la operacin, enviando el resultado y
regresar el estado de terminacin. (Fallo=0 y xito=1)
Los parmetros de entrada y retorno pueden ser definidos por el estudiante como de tipo int,
String, o el tipo de dato que desee.
Se sugiere usar sockets para resolver este primer problema y el lenguaje de su preferencia.
Y para el enfoque distribuido, generar los fragmentos de cdigo que emulen el comportamiento
de un Sub y un Skeleton, en el cliente y servidor respectivamente.
El entorno de red puede realizarse como red almbrica. No se piden 5 computadoras fsicas para
mostrarlo en funcionamiento. Entonces con 2 computadoras fsicas es suficiente y donde cada
computadora aloje 2 o 3 servidores segn convenga.

server A

server B

server C

server D

server
E

suma()

resta()

multiplica
cion()

division()

raiz()

dijkstra()

hanoi()

recursivo(
)

sort()

kerberos
()

factorial()

arbol()

ID3()

parser()

trim()

Solucin
Se propone solucionar el problema con un enfoque de objetos distribuidos. El usuario con el papel de
cliente tendr acceso a una clase Tarea, con la que podr instanciar objetos y hacer llamadas a las
funciones suma(x, y), resta(x, y), multiplicacion(x, y), y division(x, y), y como si fuera un objeto local,
recibir una respuesta. La clase Tarea funciona como un stub, ya que se intenta conectar a los
servidores externos para mandarles la informacin necesaria para la realizacin de una operacin.
La clase Tarea instanciar un socket para conectarse a un servidor al azar, y adems, otro socket para
escuchar una respuesta de parte de algn servidor. Se tendrn cuatros servidores, cada uno realizar una
operacin nica y se dedicarn a escuchar peticiones tanto del cliente como de otros servidores; a
continuacin se explica con ms detalle el diagrama de flujo.
El cliente, cuando instancia un objeto de la clase tarea automticamente crea un hilo en donde abre un
socket para escuchar la respuesta de algn servidor. La clase Tarea tiene un diccionario con las
direcciones de todos los servidores, pero sin saber qu operacin realiza cada uno. Se crea una copia
del diccionario para almacenar a los servidores por visitar. Cuando se manda a llamar un mtodo, el
cliente intenta conectarse a un servidor de forma aleatoria; si la conexin no es posible, se elimina ese

servidor del diccionario por visitar y se vuelve a intentar conectar a otro servidor al azar. Si ningn
servidor est disponible, se manda un mensaje de error. Si existe una conexin exitosa, se arma un
string en formato json en donde se indica la operacin que desea el cliente, los parmetros, la direccin
del cliente y la lista de servidores por visitar, y esto es lo que se manda por el socket. En este momento,
el cliente espera una respuesta.
El servidor recibe una peticin, e inmediatamente lee el string json para obtener la operacin deseada.
Si el servidor la sabe realizar, crea un socket para conectarse al cliente y le manda la respuesta. Si no es
as, lee del json la lista de servidores a visitar, y sigue el mismo procedimiento que el cliente para
conectarse a otro servidor dentro de la lista de servidores por vistar al azar. Si se logra hacer una
conexin, se elimina el servidor actual de la lista de servidores por visitar y se retransmite el mensaje
del cliente con la lista de servidores por visitar actualizada. Si ninguna conexin es exitosa, se conecta
al cliente mediante un socket y manda un mensaje de error.

Diagrama de flujo
Cliente

Servidor

Cdigo
Cliente
# coding=utf-8
import threading
import socket
import json
from random import randint
import time
class Tarea():
def __init__(self):
# diccionario que contiene las direcciones de todos los servidores. No se conoce
qu operacin hace cada servidor
self.direcciones = {"A": {"ip": "192.168.43.171", "puerto": 5001}, "B": {"ip":
"192.168.43.32", "puerto": 5002}, "C": {"ip": "192.168.43.249", "puerto":
5003},"D": {"ip": "localhost", "puerto": 5004}}
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # socket para
conectarse a un servidor al azar
self.por_visitar = {} # diccionario con las direcciones a visitar
self.socki = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Iniciamos un hilo que se encargar de escuchar alguna respuesta de uno de los
servidores
thread = threading.Thread(target = self.run, args = ())
thread.daemon = True
thread.start()
def run(self):
#creamos un socket que va escuchar la respuesta de algn servidor... si la hay
# Create a TCP/IP socket
server_address = ('', 5050)
self.socki.bind(server_address)
self.socki.listen(1)
while True:
connection, client_address = self.socki.accept()
respuesta = connection.recv(2048)
if respuesta:
print respuesta
connection.close()

def conectar(self):
# se intenta conectar a un servidor al azar
# si la conexion no es posible, vuelve a intentar con otro servidor hasta
encontrar uno que s acepte la conexin
self.por_visitar = self.direcciones # creamos una copia del diccionario
direcciones

flag = 0
while flag != 1:
if not self.por_visitar:
return False #si se intent visitar todos los servidores y todos
fallaron, mandar este mensaje
r = randint(0, len(self.por_visitar)-1) # generamos un numero al azar de 0
al tamao del diccionario de direcciones x visitar
try:
self.socket.connect((self.por_visitar.values()[r]["ip"],
self.por_visitar.values()[r]["puerto"])) # para acceder a un
elemento por su NDICE en vez de su KEY usamos .values()[index]
flag = 1
return True
except socket.error:
# el mtodo pop sirve para eliminar un elemento de un diccionario
mediante su KEY. Por eso como parametro se pasa
self.por_visitar.keys()[r]
self.por_visitar.pop(self.por_visitar.keys()[r], None) #si la
conexin no se puede realizar, quitamos ese servidor del
diccionario y volvemos a intentar
def suma(self, x, y):
connected = self.conectar()
if connected:
# el mensaje a mandar tiene la operacion a buscar, los parmetros, y la
direccin ip y puero del cliente
# adems, se manda el diccionario de direcciones a visitar. Si durante el
proceso de conexin a un servidor al azar
# se detectan servidores cados, se eliminan de este diccionario. Esto
reduce los servidores a visitar en este momento.
msj = {"operacion": "suma", "x": x, "y":y, "ip": "192.168.43.218",
"puerto":5050, "por_visitar": self.por_visitar} # hay que encontrar una
forma de obtener la ip de la interface automticamente
self.socket.send(json.dumps(msj))
time.sleep(60)
else:
print "Intntelo ms tarde"
def resta(self, x, y):
connected = self.conectar()
if connected:
# el mensaje a mandar tiene la operacion a buscar, los parmetros, y la
direccin ip y puero del cliente
# adems, se manda el diccionario de direcciones a visitar. Si durante el
proceso de conexin a un servidor al azar
# se detectan servidores cados, se eliminan de este diccionario. Esto
reduce los servidores a visitar en este momento.
msj = {"operacion": "resta", "x": x, "y":y, "ip": "192.168.43.218",
"puerto":5050, "por_visitar": self.por_visitar} # hay que encontrar una
forma de obtener la ip de la interface automticamente

self.socket.send(json.dumps(msj))
time.sleep(60)
else:

print "Intntelo ms tarde"

def multiplicacion(self, x, y):


connected = self.conectar()
if connected:
# el mensaje a mandar tiene la operacion a buscar, los parmetros, y la
direccin ip y puero del cliente
# adems, se manda el diccionario de direcciones a visitar. Si durante el
proceso de conexin a un servidor al azar
# se detectan servidores cados, se eliminan de este diccionario. Esto
reduce los servidores a visitar en este momento.
msj = {"operacion": "multiplicacion", "x": x, "y":y, "ip":
"192.168.43.218", "puerto":5050, "por_visitar": self.por_visitar} # hay
que encontrar una forma de obtener la ip de la interface automticamente
self.socket.send(json.dumps(msj))
time.sleep(60)
else:
print "Intntelo ms tarde"
def division(self, x, y):
connected = self.conectar()
if connected:
# el mensaje a mandar tiene la operacion a buscar, los parmetros, y la
direccin ip y puero del cliente
# adems, se manda el diccionario de direcciones a visitar. Si durante el
proceso de conexin a un servidor al azar
# se detectan servidores cados, se eliminan de este diccionario. Esto
reduce los servidores a visitar en este momento.
msj = {"operacion": "division", "x": x, "y":y, "ip": "192.168.43.218",
"puerto":5050, "por_visitar": self.por_visitar} # hay que encontrar una
forma de obtener la ip de la interface automticamente
self.socket.send(json.dumps(msj))
time.sleep(60)
else:
print "Intntelo ms tarde"

Servidor Suma
#Suma.py
# coding=utf-8
import socket
import threading
import json
from random import randint
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
name = "A"
host = ""
port = 5001
s.bind((host,port)) # creamos un socket que va a escuchar peticiones
s.listen(1)
while True:
(client, (ip, port)) = s.accept()
data = client.recv(2048) # se acepta una conexion y se recibe un mensaje
msj = json.loads(data)
if data:
print str(ip) + " quiere hacer una: ", msj['operacion']
socketCliente = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # socket para
conectarse al cliente
if msj["operacion"] == "suma": # si en el mensaje la operacion es una suma, nos
conectamos al cliente original
print "Este servidor sabe realizar esa operacion"
socketCliente.connect((msj["ip"], msj["puerto"])) # y le mandamos el
resultadode la suma
suma = msj["x"] + msj["y"]
print "El servidor se ha conectado con el cliente y le ha mandado: "
print str(msj["x"]) + " + " + str(msj["y"]) + " = " + str(suma)
socketCliente.send(str(suma))
socketCliente.close()
else: # si no se pide una suma, tenemos que visitar a otro servidor
print "Este servidor no sabe realizar esa operacion"
por_visitar = msj["por_visitar"] # recibimos la lista de
por_visitar.pop(name, None) # eliminamos del diccionario las direcciones
del servidor actual
print "Este servidor intentara conectarse a alguno de estos servidores: "
+ str(por_visitar)
time.sleep(1)
flag = 0
while flag != 1:
if not por_visitar:
resultado = False #si se intent visitar todos los servidores
y todos fallaron, mandar este mensaje
r = randint(0, len(por_visitar)-1) # generamos un numero al azar de
0 al tamao del diccionario de direcciones x visitar
try:

print "Este servidor intentara conectarse a : " +


por_visitar.values()[r]["ip"] + ":" +
str(por_visitar.values()[r]["puerto"])
time.sleep(1)
socketCliente.connect((por_visitar.values()[r]["ip"],
por_visitar.values()[r]["puerto"])) # para acceder a un
elemento por su NDICE en vez de su KEY usamos .values()
[index]
flag = 1
resultado = True
except socket.error:
# el mtodo pop sirve para eliminar un elemento de un
diccionario mediante su KEY. Por eso como parametro se pasa
self.por_visitar.keys()[r]
print "Conexion fallida"
por_visitar.pop(por_visitar.keys()[r], None) #si la conexin
no se puede realizar, quitamos ese servidor del diccionario y
volvemos a intentar
if resultado:
print "Conexion exitosa, retransmitiendo el mensaje."
msj = {"operacion": msj["operacion"], "x": msj["x"], "y":msj["y"],
"ip": msj["ip"], "puerto":msj["puerto"], "por_visitar":
por_visitar}
socketCliente.send(json.dumps(msj))
else: # si no nos pudimos conectar a ningun otro servidor, nos conectamos
al cliente original y mandamos un mensaje de error
print "Ningun servidor esta en funcionamiento :("
socketCliente.connect((msj["ip"], msj["puerto"]))
socketCliente.send("Intentelo mas tarde.")
client.close()

You might also like