Sistema de Mensajeria de Colas con ZeroMQ y Python




Ernesto Crespo
Twitter: @_seraph1
Email: ecrespo@gmail.com
Blog: http://ernesto-ecrespo.blogspot.com
Agenda
●   ¿Qué es ZeroMQ?
●   Implementar una capa de mensajes con ZeroMQ
●   Tipos de transporte
●   Patrones de mensajes
●   Seleccionar infraestructura
●   Patrones de comunicación:
    ● Patrón Solicitud/Respuesta (Request/Reply)

    ● Patrón Suscriptor/Publicador(PUB/SUB)

    ● Patrón PUSH/PULL

    ● Patrón de mensaje PAR

●   Otros ejemplos:
    ● REQ/REP y PUB/SUB

    ● Multicast

●   Benchmarks
●   Licencia
●   Referencias
¿Qué es ZeroMQ?
Es una librería asíncrona de alto rendimiento de mensajería
destinado a su uso en aplicaciones distribuidas escalables
o concurrentes.
Es una librería que soporte distintos patrones de comunicación de redes.
ZeroMQ usa colas internamente para el buffer de mensajes para no
Bloquear aplicaciones al enviar mensajes.
Rápido: 8M msg/seg ,30useg de latencia.
Licencia: LGPL
Multiplataforma y multilenguajes(más de 30 lenguajes de programación)
Implementar una capa de mensajes con ZeroMQ
Para implementar una capa de mensajes ZeroMQ se necesitan 3 pasos:

1. Seleccionar transporte (ipc,tcp,epgm,inproc y pgm).

2. Seleccionar infraestructura.

3. Seleccionar patrón de mensaje.
Tipos de transporte
ZeroMQ soporta varios estilos de capa de transporte:

●   tcp://equipo:puerto, procesos en una red TCP.
●   inproc://equipo, hilos en un proceso.
●   ipc:///tmp/archivo socket Unix que permite una comunicación
    entre procesos.
●   pgm://interface:dirección:puerto y epgm://interface:dirección:puerto
    soporta la librería OpenPGM para comunicación multicast sobre IP
    (pgm) y sobre UDP (epgm).
Patrones de mensajes

Los patrones básicos de ZeroMQ son:
● Request/Reply: bidireccional, balanceo de carga y basado en estado.

● Publish/Subscribe: publica multiples recipientes en uno.

● Push/Pull (pipeline): distribuye datos a nodos en un pipeline.

● Pair: comunicación exclusiva entre pares.
Seleccionar infraestructura
Luego de definir el tipo de transporte es necesario pensar como los
diferentes componentes se conectan.




Tipos de dispositivos:
1. Queue: un forwarder para el patrón req/resp.
2. Forwarder: un forwarder para el patrón PUB/SUB.
3. Streamer: un forwarder para el patrón pipelined.
Patrón REQ/REP
Comunicación bidireccional que facilita el balanceo de carga y se
basa en estados.

Este patrón es muy común y es normalmente usado por varios servicios
como: HTTP, POP o IMAP.
Servidor REQ/REP
#!/usr/bin/env python
#Se importa zeromq
import zmq
#Se crea la instancia del contexto de zmq.
context = zmq.Context()
#Se define el socket con parámetro respuesta REP.
socket = context.socket(zmq.REP)
#Se asocia la dirección IP y el puerto donde el servidor escucha las peticiones.
socket.bind("tcp://127.0.0.1:5000")
#Se define un contados
c=1
#Se genera un ciclo que sólo finaliza si se recibe la letra q.
while True:
   #Se recibe los mensajes.
   msg = socket.recv()
   #Se consulta si la longitud del mensaje es 1 y es la letra q se termina el ciclo
   if len(msg) == 1 and msg == "q":
       break
   #Se separa los datos que viene en un string separados por :
   datos = msg.split(":")
   #se realiza una suma con los datos recibidos.
   resultado = int(datos[0]) + int(datos[1])
   #Se muestra en pantalla el resultado
   print "Iteracion: %s ,He recibido: %s, el resultado es: %s " %(c,msg,resultado)
   #Se envía el resultado al cliente
   socket.send(str(resultado))
   #Se incrementa el contador.
   c += 1
Cliente REQ/REP
#!/usr/bin/env python
#Se importa zeromq y random
import zmq
import random
#Se crea la instancia del contexto
context = zmq.Context()
#Se crea el socket y se para el argumento de petición REQ
socket = context.socket(zmq.REQ)
#Se coencta a la IP y puerto donde escucha el servidor
socket.connect("tcp://127.0.0.1:5000")
#Se genera un ciclo de 1000 repeticiones
for i in range(1000):
  #Se crea el string con el mensaje, se pasa 2 aargumentos aleatorios
  msg = "%s:%s" %(random.randint(1, 1000),random.randint(1, 1000))
  #Se envia el mensaje al servidor
  socket.send(msg)
  #Se recibe el mensaje del servidor
  msg_in = socket.recv()
  #Se muestra en patalla los datos y el resultado
  print "Iteracion: %s, Enviado: %s, Recibido: %s" %(i,msg,msg_in)
  #Si se llea a la iteración 999 se envía la letra q para finalizar
  if i == 999: socket.send("q")
Patrón PUB/SUB
En este patrón los componentes son pobremente acoplados, son de
gran ayuda para escalar ya que no existe necesidad de preocuparse
de los suscriptores.
Se puede pensar en servicios como XMPP o twitter, donde los mensajes
sólo le llegan a las personas que les toca recibirlos.
Servidor Patrón PUB/SUB

#!/usr/bin/env python
#Se importa ZeroMQ
import zmq
#Se importa choice a partir de random
from random import choice
#Se crea la instancia del contexto
context = zmq.Context()
#Se crea el socket pasandole argumento de publicacion PUB
socket = context.socket(zmq.PUB)
#Se asocia la IP y el puerto que va a escuchar.
socket.bind("tcp://127.0.0.1:5000")
#Se importa sleep
from time import sleep
#Se crea una lista de paises y de eventos
paises = ['holanda','brasil','alemania','portugal','argentina','italia','rusia','venezuela']
eventos = ['tarjeta amarilla','tarjeta roja','gol','corner','falta']
Servidor Patrón PUB/SUB

#Se crea un contador con valor inicial 1
c=1
#Se crea un ciclo indefinido
while True:
  #Se define un mensaje pasando de forma aleatoria un pais y un evento
  mensaje = choice( paises) + " " + choice(eventos)
  #Se muestra en pantalla el valor del contador y el mensaje.
  print "->",c , mensaje
  #Se envia el mensaje
  socket.send(mensaje)
  #Se genera un retardo de 1 seg
  sleep(1)
  #Se incrementa el contador
  c += 1
  #Si se llega a 180 se termina el ciclo si no continua.
  if c == 180:
     break
  else:
     continue
#!/usr/bin/env python
                               Cliente 1 Patrón PUB/SUB
#Se importa zeroMQ
import zmq
#Se importa sleep a partir de time
from time import sleep
#Se crea la instancia del contexto de zeroMQ
context = zmq.Context()
#Se crea el socket del suscriptor SUB
socket = context.socket(zmq.SUB)
#Se crea la conexion a la IP y puerto del servidor
socket.connect("tcp://127.0.0.1:5000")
#Se define una opcion del socket del suscriptor con argentina y venezuela
socket.setsockopt(zmq.SUBSCRIBE, "argentina")
socket.setsockopt(zmq.SUBSCRIBE, "venezuela")
#Se define el valor inicial de un contador
c=1
#Se crea un ciclo indefinido
while True:
   #Se muestra en pantalla el valor del contador y el mensaje recibido
   print c, "->",socket.recv()
   #Se genera un retardo de 1 seg en cada ciclo
   sleep(1)
   #Se incrementa el contador en 1
   c += 1
   #Si el contador llega a 90 se termina el ciclo, si no continua
   if c == 90:
      break
   else:
      continue
#!/usr/bin/env python
                                Cliente 2 Patrón PUB/SUB
#Se importa zeroMQ
import zmq
#Se importa sleep a partir de time
from time import sleep
#Se crea la instancia del contexto de zeroMQ
context = zmq.Context()
#Se crea el socket del suscriptor SUB
socket = context.socket(zmq.SUB)
#Se crea la conexion a la IP y puerto del servidor
socket.connect("tcp://127.0.0.1:5000")
#Se define una opcion del socket del suscriptor con brasil y alemania
socket.setsockopt(zmq.SUBSCRIBE, "brasil")
socket.setsockopt(zmq.SUBSCRIBE, "alemania")
#Se define el valor inicial de un contador
c=1
#Se crea un ciclo indefinido
while True:
   #Se muestra en pantalla el valor del contador y el mensaje recibido
   print c, "->",socket.recv()
   #Se genera un retardo de 1 seg en cada ciclo
   sleep(1)
   #Se incrementa el contador en 1
   c += 1
   #Si el contador llega a 90 se termina el ciclo, si no continua
   if c == 90:
      break
   else:
      continue
Emisor, ejemplo Patrón PUSH/PULL
#!/usr/bin/python
#Se importa zeroMQ y random
import zmq
import random
#Se crea la instancia del contexto
context = zmq.Context()
#Se crea el socket con el argumento PUSH
envio =context.socket(zmq.PUSH)
#Se asocia el socket a escuchar todas las IPs y el puerto 5557
envio.bind("tcp://*:5557")
#se muestra que es necesario esperar que arranquen los workers
print "Hay que esperar que los workers se inicien"
#Al dar enter se inicia el proceso de transmision
raw_input()
print "Se inicia la transmision del trabajo..."
#tupla de strings que se van a enviar
cadenas = ['hola', 'aloha','hello','buenas noches','buenas tardes','buenos dias','bienvenido']
#Se crea un ciclo para recorrer la tupla
for i in range(len(cadenas)):
 cadena = cadenas[i]
 envio.send(cadena)
 print "Enviando: {0}".format(cadena)
Workers, ejemplo Patrón PUSH/PULL
#!/usr/bin/python
#Se importa ZeroMQ y sleep de time
import zmq
from time import sleep
#Se crea la instancia del contexto
context = zmq.Context()
#Se define el Socket con argumento PULL
recepcion = context.socket(zmq.PULL)
#Se conecta el socket a localhost puerto 5557
#Es el puerto donde origen envia con PUSH los datos
recepcion.connect("tcp://localhost:5557")
#Se crea el socket de envio de los datos procesados con argumento PUSH
envio = context.socket(zmq.PUSH)
#Se conecta el socket a localhost y puerto 5558
envio.connect("tcp://localhost:5558")
#Se genera un ciclo
#donde se recive lo transmitido por origen
#se procesa (se coloca en mayusculas)
#se muestra en pantalla y se envia.
#los ciclos tienen un retardo de 1 seg
while True:
 cadena = recepcion.recv()
 print "Proceso:{0}".format(cadena)
 envio.send(cadena.upper())
 sleep(1)
Resultado, ejemplo Patrón PUSH/PULL
#!/usr/bin/python
#Se importa ZeroMQ
import zmq
#Se crea la instancia del contexto
context = zmq.Context()
#Se crea el socket PULL que recibe los mensajes de los workers
recepcion = context.socket(zmq.PULL)
#Se asocia el socket a escuchar todas las IPs en el puerto 5558
#el puerto donde los workers envian los mensajes
recepcion.bind("tcp://*:5558")
#Se inicia un ciclo donde se recibe los mensajes
#de los workers y se muestra en pantalla
while True:
 mensaje = recepcion.recv()
 print "Recibo: {0}".format(mensaje)
Patrón Pair
Comunicación exlusiva entre pares.
Lo que se logra es que si otro nodo intenta conectarse no lo logrará si
no está declarado.
Si está declarado, este establece conexión pero saca al nodo anterior.
Servidor Patrón Pair

#!/usr/bin/env python

#Importar zmq
import zmq
#Se crea la instancia del contexto
context = zmq.Context()
#Se crea el socket del tipo PAR
socket = context.socket(zmq.PAIR)
#Se asocia a una IP y puerto donde escucha el servidor.
socket.bind("tcp://127.0.0.1:5555")
#Se crea un ciclo.
while True:
  #Se recibe un mensaje del cliente
  mensaje = socket.recv()
  #Se muestra en pantalla
  print "Recivo", mensaje
  #Se envia de vuelta el mensaje
  socket.send(mensaje)
Cliente Patrón Pair

#!/usr/bin/env python
#Se importa zmq
import zmq
#Se crea la instancia del contexto
context = zmq.Context()
#Se crea el socket con argumento del tipo de mensaje Par.
socket = context.socket(zmq.PAIR)
#Se conecta al servidor dado la IP y puerto.
socket.connect("tcp://127.0.0.1:5555")
#Se crea un cilo de 100 repeticiones.
for i in range(100):
   #Se define el mensaje a pasar
   mensaje = "mensaje %s" % i
   #Se pasa el mensaje al servidor
   socket.send(mensaje)
   #Se presenta en pantalla el mensaje
   print "Enviando", mensaje
   #Se recibe el mensaje de vuelta
   msg_in = socket.recv()
   #Se presenta en pantalla el mensaje de vuelta
   print "Recibido:", msg_in
Patrones REQ/REP y PUB/SUB
 Emisor
#!/usr/bin/python
#Se importa zeroMQ
import zmq
#Se crea el contexto
context = zmq.Context()
#Se crea el socket con el parametro REQ
socket = context.socket(zmq.REQ)
#Se asocia la IP y el puerto del socket.
socket.connect("tcp://127.0.0.1:4000")
#Se genera los mensajes estilo tuiter y se envia al socket.
for i in ['@_seraph1 Esta es una prueba','@otro viendo el juego', '@_seraph1 otra prueba','@otro otro']:
 socket.send(i)
 msg_in = socket.recv()
Patrones REQ/REP y PUB/SUB
 Tuiter
#!/usr/bin/env python
#Se importa zeroMQ
import zmq
#Se importa choice de random
from random import choice
#Se crea el contexto
context = zmq.Context()
#Se define el socket de recepcion con argumento REP
socket_recv = context.socket(zmq.REP)
#Se asocia a una IP y puerto el socket de recepcion
socket_recv.bind("tcp://127.0.0.1:4000")
#Se define el socket de publicacion con argumento PUB
socket = context.socket(zmq.PUB)
#Se asocia la ip y un puerto distinto al anterio socket
socket.bind("tcp://127.0.0.1:5000")
#Se crea un ciclo
while True:
 #Se recibe el mensaje del socket de recepcion
 msg = socket_recv.recv()
 #Se envia el mensaje de recepcion
 socket_recv.send(msg)
 #Se muestra el mensaje en pantalla
 print "Reenvio: {0}".format(msg)
 #Se envia el mensaje al socket de publicacion
 socket.send(msg)
Patrones REQ/REP y PUB/SUB
 Receptor 1:
#!/usr/bin/python
#Se importa zeroMQ
import zmq
#Se crea el contexto
context = zmq.Context()
#Se crea el socket de suscripcion
socket = context.socket(zmq.SUB)
#Se asocia ese socket a la IP y puerto donde publica tuiter
socket.connect("tcp://127.0.0.1:5000")
#Se suscribe a escuchar los mensajes de @_seraph1
socket.setsockopt(zmq.SUBSCRIBE, "@_seraph1")
#se crea un ciclo donde se recibe los mensajes
while True:
 print "->",socket.recv()
Patrones REQ/REP y PUB/SUB
 Receptor 2:
#!/usr/bin/python
#Se importa zeroMQ
import zmq
#Se crea el contexto
context = zmq.Context()
#Se crea el socket de suscripcion
socket = context.socket(zmq.SUB)
#Se asocia ese socket a la IP y puerto donde publica tuiter
socket.connect("tcp://127.0.0.1:5000")
#Se suscribe a escuchar los mensajes de @otro
socket.setsockopt(zmq.SUBSCRIBE, "@otro")
#se crea un ciclo donde se recibe los mensajes
while True:
 print "->",socket.recv()
Multicast
 Productor:
#!/usr/bin/env python
#
# producer
#Se importa ZeroMQ
import zmq
#Se crea la instancia de la clase Context.
context = zmq.Context()
#Se define el socket con parametro PUB
socket = context.socket(zmq.PUB)
#Se define unas opciones en el socket
#esta opcion LINGER con valor cero, descarta mensajes no enviados
socket.setsockopt(zmq.LINGER, 0)
#Se conecta al socket a la IP y puerto
#por medio de multicast
socket.connect('epgm://192.168.10.96:5000')
#Se crea un ciclo
#si se envia el texto salir, se envia y luego finaliza el ciclo
#si no, se envia el texto
while True:
 mensaje = raw_input("->")
 print mensaje
 socket.send(mensaje)
 if mensaje == "salir": break
socket.close()
Multicast
 Consumidor:
#!/usr/bin/env python
#Importar zeroMQ
import zmq
#Se crea la instancia de la clase contexto
context = zmq.Context()
#Se define el socket con parametro SUB
socket = context.socket(zmq.SUB)
#Se conecta el socket a la IP y puerto del productor
#con el transporte epgm
socket.connect('epgm://192.168.10.96:5000')
#Se define los textos que se recibe la informacion.
#prueba, hora y salir.
socket.setsockopt(zmq.SUBSCRIBE, 'prueba')
socket.setsockopt(zmq.SUBSCRIBE, 'hora')
socket.setsockopt(zmq.SUBSCRIBE, 'salir')
#Se define un ciclo,
#se recibe la informacion
#Si el texto es salir se muestra en pantalla
#finaliza el ciclo, si no se muestra
#el texto en pantalla
while True:
   rcv = socket.recv()
   print rcv
   if rcv == "salir": beak
Benchmark




http://mikehadlow.blogspot.com/2011/04/message-queue-shootout.html
Licencia


Este documento está licenciado bajo la GNU Free Documentation
License (GFDL). www.gnu.org
Se autoriza la copia y distribución por cualquier medio, siempre
que se realice bajo esta misma licencia, se mencione al autor
original y se incluya esta nota.
Referencias:

●   http://nichol.as/zeromq-an-introduction

●   http://blog.pythonisito.com/2012/08/distributed-systems-with-zeromq.html

●   http://mikehadlow.blogspot.com/2011/04/message-queue-shootout.html

●   http://pop-servis.blogspot.com/2011/04/benchmarking-zeromq-over-network.html

●   http://ernesto-ecrespo.blogspot.com/search/label/ZeroMQ

●   http://www.zeromq.org/results:multicore-tests

●   http://www.zeromq.org/results:10gbe-tests-v031

●   http://blog.pythonisito.com/2012/08/zeromq-flow-control-and-other-options.html#more

Sistema de Mensajeria de Colas con ZeroMQ y Python

  • 1.
    Sistema de Mensajeriade Colas con ZeroMQ y Python Ernesto Crespo Twitter: @_seraph1 Email: ecrespo@gmail.com Blog: http://ernesto-ecrespo.blogspot.com
  • 2.
    Agenda ● ¿Qué es ZeroMQ? ● Implementar una capa de mensajes con ZeroMQ ● Tipos de transporte ● Patrones de mensajes ● Seleccionar infraestructura ● Patrones de comunicación: ● Patrón Solicitud/Respuesta (Request/Reply) ● Patrón Suscriptor/Publicador(PUB/SUB) ● Patrón PUSH/PULL ● Patrón de mensaje PAR ● Otros ejemplos: ● REQ/REP y PUB/SUB ● Multicast ● Benchmarks ● Licencia ● Referencias
  • 3.
    ¿Qué es ZeroMQ? Esuna librería asíncrona de alto rendimiento de mensajería destinado a su uso en aplicaciones distribuidas escalables o concurrentes. Es una librería que soporte distintos patrones de comunicación de redes. ZeroMQ usa colas internamente para el buffer de mensajes para no Bloquear aplicaciones al enviar mensajes. Rápido: 8M msg/seg ,30useg de latencia. Licencia: LGPL Multiplataforma y multilenguajes(más de 30 lenguajes de programación)
  • 4.
    Implementar una capade mensajes con ZeroMQ Para implementar una capa de mensajes ZeroMQ se necesitan 3 pasos: 1. Seleccionar transporte (ipc,tcp,epgm,inproc y pgm). 2. Seleccionar infraestructura. 3. Seleccionar patrón de mensaje.
  • 5.
    Tipos de transporte ZeroMQsoporta varios estilos de capa de transporte: ● tcp://equipo:puerto, procesos en una red TCP. ● inproc://equipo, hilos en un proceso. ● ipc:///tmp/archivo socket Unix que permite una comunicación entre procesos. ● pgm://interface:dirección:puerto y epgm://interface:dirección:puerto soporta la librería OpenPGM para comunicación multicast sobre IP (pgm) y sobre UDP (epgm).
  • 6.
    Patrones de mensajes Lospatrones básicos de ZeroMQ son: ● Request/Reply: bidireccional, balanceo de carga y basado en estado. ● Publish/Subscribe: publica multiples recipientes en uno. ● Push/Pull (pipeline): distribuye datos a nodos en un pipeline. ● Pair: comunicación exclusiva entre pares.
  • 7.
    Seleccionar infraestructura Luego dedefinir el tipo de transporte es necesario pensar como los diferentes componentes se conectan. Tipos de dispositivos: 1. Queue: un forwarder para el patrón req/resp. 2. Forwarder: un forwarder para el patrón PUB/SUB. 3. Streamer: un forwarder para el patrón pipelined.
  • 8.
    Patrón REQ/REP Comunicación bidireccionalque facilita el balanceo de carga y se basa en estados. Este patrón es muy común y es normalmente usado por varios servicios como: HTTP, POP o IMAP.
  • 9.
    Servidor REQ/REP #!/usr/bin/env python #Seimporta zeromq import zmq #Se crea la instancia del contexto de zmq. context = zmq.Context() #Se define el socket con parámetro respuesta REP. socket = context.socket(zmq.REP) #Se asocia la dirección IP y el puerto donde el servidor escucha las peticiones. socket.bind("tcp://127.0.0.1:5000") #Se define un contados c=1 #Se genera un ciclo que sólo finaliza si se recibe la letra q. while True: #Se recibe los mensajes. msg = socket.recv() #Se consulta si la longitud del mensaje es 1 y es la letra q se termina el ciclo if len(msg) == 1 and msg == "q": break #Se separa los datos que viene en un string separados por : datos = msg.split(":") #se realiza una suma con los datos recibidos. resultado = int(datos[0]) + int(datos[1]) #Se muestra en pantalla el resultado print "Iteracion: %s ,He recibido: %s, el resultado es: %s " %(c,msg,resultado) #Se envía el resultado al cliente socket.send(str(resultado)) #Se incrementa el contador. c += 1
  • 10.
    Cliente REQ/REP #!/usr/bin/env python #Seimporta zeromq y random import zmq import random #Se crea la instancia del contexto context = zmq.Context() #Se crea el socket y se para el argumento de petición REQ socket = context.socket(zmq.REQ) #Se coencta a la IP y puerto donde escucha el servidor socket.connect("tcp://127.0.0.1:5000") #Se genera un ciclo de 1000 repeticiones for i in range(1000): #Se crea el string con el mensaje, se pasa 2 aargumentos aleatorios msg = "%s:%s" %(random.randint(1, 1000),random.randint(1, 1000)) #Se envia el mensaje al servidor socket.send(msg) #Se recibe el mensaje del servidor msg_in = socket.recv() #Se muestra en patalla los datos y el resultado print "Iteracion: %s, Enviado: %s, Recibido: %s" %(i,msg,msg_in) #Si se llea a la iteración 999 se envía la letra q para finalizar if i == 999: socket.send("q")
  • 11.
    Patrón PUB/SUB En estepatrón los componentes son pobremente acoplados, son de gran ayuda para escalar ya que no existe necesidad de preocuparse de los suscriptores. Se puede pensar en servicios como XMPP o twitter, donde los mensajes sólo le llegan a las personas que les toca recibirlos.
  • 12.
    Servidor Patrón PUB/SUB #!/usr/bin/envpython #Se importa ZeroMQ import zmq #Se importa choice a partir de random from random import choice #Se crea la instancia del contexto context = zmq.Context() #Se crea el socket pasandole argumento de publicacion PUB socket = context.socket(zmq.PUB) #Se asocia la IP y el puerto que va a escuchar. socket.bind("tcp://127.0.0.1:5000") #Se importa sleep from time import sleep #Se crea una lista de paises y de eventos paises = ['holanda','brasil','alemania','portugal','argentina','italia','rusia','venezuela'] eventos = ['tarjeta amarilla','tarjeta roja','gol','corner','falta']
  • 13.
    Servidor Patrón PUB/SUB #Secrea un contador con valor inicial 1 c=1 #Se crea un ciclo indefinido while True: #Se define un mensaje pasando de forma aleatoria un pais y un evento mensaje = choice( paises) + " " + choice(eventos) #Se muestra en pantalla el valor del contador y el mensaje. print "->",c , mensaje #Se envia el mensaje socket.send(mensaje) #Se genera un retardo de 1 seg sleep(1) #Se incrementa el contador c += 1 #Si se llega a 180 se termina el ciclo si no continua. if c == 180: break else: continue
  • 14.
    #!/usr/bin/env python Cliente 1 Patrón PUB/SUB #Se importa zeroMQ import zmq #Se importa sleep a partir de time from time import sleep #Se crea la instancia del contexto de zeroMQ context = zmq.Context() #Se crea el socket del suscriptor SUB socket = context.socket(zmq.SUB) #Se crea la conexion a la IP y puerto del servidor socket.connect("tcp://127.0.0.1:5000") #Se define una opcion del socket del suscriptor con argentina y venezuela socket.setsockopt(zmq.SUBSCRIBE, "argentina") socket.setsockopt(zmq.SUBSCRIBE, "venezuela") #Se define el valor inicial de un contador c=1 #Se crea un ciclo indefinido while True: #Se muestra en pantalla el valor del contador y el mensaje recibido print c, "->",socket.recv() #Se genera un retardo de 1 seg en cada ciclo sleep(1) #Se incrementa el contador en 1 c += 1 #Si el contador llega a 90 se termina el ciclo, si no continua if c == 90: break else: continue
  • 15.
    #!/usr/bin/env python Cliente 2 Patrón PUB/SUB #Se importa zeroMQ import zmq #Se importa sleep a partir de time from time import sleep #Se crea la instancia del contexto de zeroMQ context = zmq.Context() #Se crea el socket del suscriptor SUB socket = context.socket(zmq.SUB) #Se crea la conexion a la IP y puerto del servidor socket.connect("tcp://127.0.0.1:5000") #Se define una opcion del socket del suscriptor con brasil y alemania socket.setsockopt(zmq.SUBSCRIBE, "brasil") socket.setsockopt(zmq.SUBSCRIBE, "alemania") #Se define el valor inicial de un contador c=1 #Se crea un ciclo indefinido while True: #Se muestra en pantalla el valor del contador y el mensaje recibido print c, "->",socket.recv() #Se genera un retardo de 1 seg en cada ciclo sleep(1) #Se incrementa el contador en 1 c += 1 #Si el contador llega a 90 se termina el ciclo, si no continua if c == 90: break else: continue
  • 16.
    Emisor, ejemplo PatrónPUSH/PULL #!/usr/bin/python #Se importa zeroMQ y random import zmq import random #Se crea la instancia del contexto context = zmq.Context() #Se crea el socket con el argumento PUSH envio =context.socket(zmq.PUSH) #Se asocia el socket a escuchar todas las IPs y el puerto 5557 envio.bind("tcp://*:5557") #se muestra que es necesario esperar que arranquen los workers print "Hay que esperar que los workers se inicien" #Al dar enter se inicia el proceso de transmision raw_input() print "Se inicia la transmision del trabajo..." #tupla de strings que se van a enviar cadenas = ['hola', 'aloha','hello','buenas noches','buenas tardes','buenos dias','bienvenido'] #Se crea un ciclo para recorrer la tupla for i in range(len(cadenas)): cadena = cadenas[i] envio.send(cadena) print "Enviando: {0}".format(cadena)
  • 17.
    Workers, ejemplo PatrónPUSH/PULL #!/usr/bin/python #Se importa ZeroMQ y sleep de time import zmq from time import sleep #Se crea la instancia del contexto context = zmq.Context() #Se define el Socket con argumento PULL recepcion = context.socket(zmq.PULL) #Se conecta el socket a localhost puerto 5557 #Es el puerto donde origen envia con PUSH los datos recepcion.connect("tcp://localhost:5557") #Se crea el socket de envio de los datos procesados con argumento PUSH envio = context.socket(zmq.PUSH) #Se conecta el socket a localhost y puerto 5558 envio.connect("tcp://localhost:5558") #Se genera un ciclo #donde se recive lo transmitido por origen #se procesa (se coloca en mayusculas) #se muestra en pantalla y se envia. #los ciclos tienen un retardo de 1 seg while True: cadena = recepcion.recv() print "Proceso:{0}".format(cadena) envio.send(cadena.upper()) sleep(1)
  • 18.
    Resultado, ejemplo PatrónPUSH/PULL #!/usr/bin/python #Se importa ZeroMQ import zmq #Se crea la instancia del contexto context = zmq.Context() #Se crea el socket PULL que recibe los mensajes de los workers recepcion = context.socket(zmq.PULL) #Se asocia el socket a escuchar todas las IPs en el puerto 5558 #el puerto donde los workers envian los mensajes recepcion.bind("tcp://*:5558") #Se inicia un ciclo donde se recibe los mensajes #de los workers y se muestra en pantalla while True: mensaje = recepcion.recv() print "Recibo: {0}".format(mensaje)
  • 19.
    Patrón Pair Comunicación exlusivaentre pares. Lo que se logra es que si otro nodo intenta conectarse no lo logrará si no está declarado. Si está declarado, este establece conexión pero saca al nodo anterior.
  • 20.
    Servidor Patrón Pair #!/usr/bin/envpython #Importar zmq import zmq #Se crea la instancia del contexto context = zmq.Context() #Se crea el socket del tipo PAR socket = context.socket(zmq.PAIR) #Se asocia a una IP y puerto donde escucha el servidor. socket.bind("tcp://127.0.0.1:5555") #Se crea un ciclo. while True: #Se recibe un mensaje del cliente mensaje = socket.recv() #Se muestra en pantalla print "Recivo", mensaje #Se envia de vuelta el mensaje socket.send(mensaje)
  • 21.
    Cliente Patrón Pair #!/usr/bin/envpython #Se importa zmq import zmq #Se crea la instancia del contexto context = zmq.Context() #Se crea el socket con argumento del tipo de mensaje Par. socket = context.socket(zmq.PAIR) #Se conecta al servidor dado la IP y puerto. socket.connect("tcp://127.0.0.1:5555") #Se crea un cilo de 100 repeticiones. for i in range(100): #Se define el mensaje a pasar mensaje = "mensaje %s" % i #Se pasa el mensaje al servidor socket.send(mensaje) #Se presenta en pantalla el mensaje print "Enviando", mensaje #Se recibe el mensaje de vuelta msg_in = socket.recv() #Se presenta en pantalla el mensaje de vuelta print "Recibido:", msg_in
  • 22.
    Patrones REQ/REP yPUB/SUB Emisor #!/usr/bin/python #Se importa zeroMQ import zmq #Se crea el contexto context = zmq.Context() #Se crea el socket con el parametro REQ socket = context.socket(zmq.REQ) #Se asocia la IP y el puerto del socket. socket.connect("tcp://127.0.0.1:4000") #Se genera los mensajes estilo tuiter y se envia al socket. for i in ['@_seraph1 Esta es una prueba','@otro viendo el juego', '@_seraph1 otra prueba','@otro otro']: socket.send(i) msg_in = socket.recv()
  • 23.
    Patrones REQ/REP yPUB/SUB Tuiter #!/usr/bin/env python #Se importa zeroMQ import zmq #Se importa choice de random from random import choice #Se crea el contexto context = zmq.Context() #Se define el socket de recepcion con argumento REP socket_recv = context.socket(zmq.REP) #Se asocia a una IP y puerto el socket de recepcion socket_recv.bind("tcp://127.0.0.1:4000") #Se define el socket de publicacion con argumento PUB socket = context.socket(zmq.PUB) #Se asocia la ip y un puerto distinto al anterio socket socket.bind("tcp://127.0.0.1:5000") #Se crea un ciclo while True: #Se recibe el mensaje del socket de recepcion msg = socket_recv.recv() #Se envia el mensaje de recepcion socket_recv.send(msg) #Se muestra el mensaje en pantalla print "Reenvio: {0}".format(msg) #Se envia el mensaje al socket de publicacion socket.send(msg)
  • 24.
    Patrones REQ/REP yPUB/SUB Receptor 1: #!/usr/bin/python #Se importa zeroMQ import zmq #Se crea el contexto context = zmq.Context() #Se crea el socket de suscripcion socket = context.socket(zmq.SUB) #Se asocia ese socket a la IP y puerto donde publica tuiter socket.connect("tcp://127.0.0.1:5000") #Se suscribe a escuchar los mensajes de @_seraph1 socket.setsockopt(zmq.SUBSCRIBE, "@_seraph1") #se crea un ciclo donde se recibe los mensajes while True: print "->",socket.recv()
  • 25.
    Patrones REQ/REP yPUB/SUB Receptor 2: #!/usr/bin/python #Se importa zeroMQ import zmq #Se crea el contexto context = zmq.Context() #Se crea el socket de suscripcion socket = context.socket(zmq.SUB) #Se asocia ese socket a la IP y puerto donde publica tuiter socket.connect("tcp://127.0.0.1:5000") #Se suscribe a escuchar los mensajes de @otro socket.setsockopt(zmq.SUBSCRIBE, "@otro") #se crea un ciclo donde se recibe los mensajes while True: print "->",socket.recv()
  • 26.
    Multicast Productor: #!/usr/bin/env python # #producer #Se importa ZeroMQ import zmq #Se crea la instancia de la clase Context. context = zmq.Context() #Se define el socket con parametro PUB socket = context.socket(zmq.PUB) #Se define unas opciones en el socket #esta opcion LINGER con valor cero, descarta mensajes no enviados socket.setsockopt(zmq.LINGER, 0) #Se conecta al socket a la IP y puerto #por medio de multicast socket.connect('epgm://192.168.10.96:5000') #Se crea un ciclo #si se envia el texto salir, se envia y luego finaliza el ciclo #si no, se envia el texto while True: mensaje = raw_input("->") print mensaje socket.send(mensaje) if mensaje == "salir": break socket.close()
  • 27.
    Multicast Consumidor: #!/usr/bin/env python #ImportarzeroMQ import zmq #Se crea la instancia de la clase contexto context = zmq.Context() #Se define el socket con parametro SUB socket = context.socket(zmq.SUB) #Se conecta el socket a la IP y puerto del productor #con el transporte epgm socket.connect('epgm://192.168.10.96:5000') #Se define los textos que se recibe la informacion. #prueba, hora y salir. socket.setsockopt(zmq.SUBSCRIBE, 'prueba') socket.setsockopt(zmq.SUBSCRIBE, 'hora') socket.setsockopt(zmq.SUBSCRIBE, 'salir') #Se define un ciclo, #se recibe la informacion #Si el texto es salir se muestra en pantalla #finaliza el ciclo, si no se muestra #el texto en pantalla while True: rcv = socket.recv() print rcv if rcv == "salir": beak
  • 28.
  • 29.
    Licencia Este documento estálicenciado bajo la GNU Free Documentation License (GFDL). www.gnu.org Se autoriza la copia y distribución por cualquier medio, siempre que se realice bajo esta misma licencia, se mencione al autor original y se incluya esta nota.
  • 30.
    Referencias: ● http://nichol.as/zeromq-an-introduction ● http://blog.pythonisito.com/2012/08/distributed-systems-with-zeromq.html ● http://mikehadlow.blogspot.com/2011/04/message-queue-shootout.html ● http://pop-servis.blogspot.com/2011/04/benchmarking-zeromq-over-network.html ● http://ernesto-ecrespo.blogspot.com/search/label/ZeroMQ ● http://www.zeromq.org/results:multicore-tests ● http://www.zeromq.org/results:10gbe-tests-v031 ● http://blog.pythonisito.com/2012/08/zeromq-flow-control-and-other-options.html#more