CLOUD COMPUTING.DESARROLLO DE APLICACIONES Y
MINERÍA WEB
Miguel Fernández Fernández [email protected]
Programa de extensión universitariaUniversidad de Oviedo
Web en Tiempo RealXMPP, Websockets, et al.
¿Qué es XMPP?
Extensible Messaging and Presence Protocol
Envío de mensajes en tiempo real
Codificados en XML
Transportados sobre TCP y UDP (media)
antesJabber
http://xmpp.org
¿Por qué XMPP?HTTP
Half-duplex
para la Web
stateless
¿Por qué XMPP?HTTP
Half-duplex
c
snormal polling (AJAX)
c
slong polling (Comet)
para la Web
stateless
¿Por qué XMPP?HTTP
Half-duplex
c
snormal polling (AJAX)
c
slong polling (Comet)
para la Web
stateless
XMPP
Full-duplex
stateful
¿Por qué XMPP?HTTP
Half-duplex
c
snormal polling (AJAX)
c
slong polling (Comet)
para la Web
stateless
XMPP
Full-duplex
stateful
c
sconexión persistente
Arquitectura XMPP
O’REILLY XMPP: The Definitive Guide
Arquitectura XMPP
Web (HTTP) Mail (SMTP)
XMPP
La red XMPP: Entidades
Servidores
Plugins
Componentes
Clientes
Servidores
Enrutan mensajes
Hablan con clientes y otros servidores
FOSS: Ejabberd, Openfire, Tigase
Clientes
Humanos y robots
Protocolo cliente-servidor
Componentes
Extienden la funcionalidad del servidor
Tienen su propia identidad y dirección
Se ejecutan fuera del mismo
Se comunican con un protocolo específico
Ejemplo típico: Multichat
Plugins
Mismo propósito que los componentes
También tienen identidad y dirección
No hay IPC mayor rendimiento
Direccionamiento en XMPP
JIDs: almenos uno por cada entidad
[email protected]/[email protected]/adium
Bare JID
Full JID
XMPP Stanzas
<stream:stream>
<iq type="get"> <query xmlns="jabber:iq:roster"/> </iq>
<presence/>
<message to="[email protected]" from="[email protected]/adium" type="chat"> <body>Tomamos algo?</body> </message>
<presence type="unavailable"/>
</stream:stream>
XMPP Stanzas
<stream:stream>
<iq type="get"> <query xmlns="jabber:iq:roster"/> </iq>
<presence/>
<message to="[email protected]" from="[email protected]/adium" type="chat"> <body>Tomamos algo?</body> </message>
<presence type="unavailable"/>
</stream:stream>
XMPP Stanzas
<stream:stream>
<iq type="get"> <query xmlns="jabber:iq:roster"/> </iq>
<presence/>
<message to="[email protected]" from="[email protected]/adium" type="chat"> <body>Tomamos algo?</body> </message>
<presence type="unavailable"/>
</stream:stream>
Dame mis contactos
XMPP Stanzas
<stream:stream>
<iq type="get"> <query xmlns="jabber:iq:roster"/> </iq>
<presence/>
<message to="[email protected]" from="[email protected]/adium" type="chat"> <body>Tomamos algo?</body> </message>
<presence type="unavailable"/>
</stream:stream>
Dame mis contactos
Estoy online
XMPP Stanzas
<stream:stream>
<iq type="get"> <query xmlns="jabber:iq:roster"/> </iq>
<presence/>
<message to="[email protected]" from="[email protected]/adium" type="chat"> <body>Tomamos algo?</body> </message>
<presence type="unavailable"/>
</stream:stream>
Dame mis contactos
Estoy online
Dile a bar que si tomamos algo
XMPP Stanzas
<stream:stream>
<iq type="get"> <query xmlns="jabber:iq:roster"/> </iq>
<presence/>
<message to="[email protected]" from="[email protected]/adium" type="chat"> <body>Tomamos algo?</body> </message>
<presence type="unavailable"/>
</stream:stream>
Dame mis contactos
Estoy online
Dile a bar que si tomamos algoYa no estoy disponible
Tiempo real en La Web
Acercando XMPP a la Web
Pre HTML 5
Comunicación basada en HTTP
Bidirectional-Streams over synchronous HTTP
AJAX & Long Polling
AJAX & Long Polling
setInterval(function(){ // pedimos cada 500 milisegundos esperando cambio $.ajax({ url: '/my/page', success: function(data){} });}, 500);
function load(){ $.ajax({ url: '/my/page', success: function(){ // abrimos la conexión durante 20 segundos }, complete: load, timeout: 20000 });}
AJAX (muestreo frecuente) Comet (Long Polling)
Latencia (200ms/petición)
Muchas peticiones no recogeran cambios
Se genera mucho tráfico
Reducción dramática de latencia
Mucho más eficiente
BOSH, XMPP sobre HTTP
http://xmpp.org/extensions/xep-0206.html
Flujos bidireccionales sobre HTTP síncrono
Usa pares de petición-respuesta para simular
Requiere de un proxy que dirija los stanzas al servidor XMPP
HTTP/1.1 200 OKContent-Type: text/xml; charset=utf-8Content-Length: 483
<body xmpp:version='1.0' authid='ServerStreamID' xmlns='http://jabber.org/protocol/httpbind' xmlns:xmpp='urn:xmpp:xbosh' xmlns:stream='http://etherx.jabber.org/streams'> <stream:features> <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <mechanism>SCRAM-SHA-1</mechanism> <mechanism>PLAIN</mechanism> </mechanisms> </stream:features></body>
HTML5 WebsocketsHTML 5
WebSocketsTo enable Web applications to maintain bidirectional
communications with server-side processes, this specification introduces the WebSocket interface.
Gecko 2.0b4 (24/08/2010) (Firefox 4 Nighties)Webkit 333 (Safari 4, Chrome >4)Soportado en:
HTML5 WebsocketsHTML 5
WebSocketsTo enable Web applications to maintain bidirectional
communications with server-side processes, this specification introduces the WebSocket interface.
Gecko 2.0b4 (24/08/2010) (Firefox 4 Nighties)Webkit 333 (Safari 4, Chrome >4)Soportado en:
c
sconexión persistente
El contrato Websocket[Constructor(in DOMString url, in optional DOMString protocols)][Constructor(in DOMString url, in optional DOMString[] protocols)]interface WebSocket { readonly attribute DOMString url;
// ready state const unsigned short CONNECTING = 0; const unsigned short OPEN = 1; const unsigned short CLOSING = 2; const unsigned short CLOSED = 3; readonly attribute unsigned short readyState; readonly attribute unsigned long bufferedAmount;
// networking attribute Function onopen; attribute Function onmessage; attribute Function onerror; attribute Function onclose; readonly attribute DOMString protocol; void send(in DOMString data); void close();};WebSocket implements EventTarget;
estado de la conexión
Recepción de eventos
Envío de mensajes
ws://services.com/service
Web en tiempo real con Websockets
Event Machine
http://rubyeventmachine.com/
Framework I/O dirigida por eventos
Corre sobre ruby
à-la node.js (javascript) y twisted (python)
Implementa el patrón Reactor
Muy útil para crear aplicaciones servidor
eventmachine (0.12.10)eventmachine-websocket (0.1.0)
Nuestro cliente<html> <head> <script src='jquery.min.js'></script> <script> function WebSocketAdapter(url){ this.ws=new WebSocket(url); this.ws.onmessage = function(evt) {$("#msg").append("<p>"+evt.data+"</p>");}; this.ws.onclose = function() { alert("socket cerrado"); }; this.ws.onopen = function() { alert("conectado..."); }; this.send=function(msg) {this.ws.send(msg);} } var ws; $(document).ready(function(){ ws=new WebSocketAdapter("ws://localhost:8080/"); }); </script> </head> <body> <form> Enviar al servidor: <input id="texto" type="text" value="hola mundo!"></input> <input id="enviar" type="button" value="enviar" onclick="ws.send($('#texto').val())"/> </form> <div id="msg"></div> </body></html>
Nuestro cliente<html> <head> <script src='jquery.min.js'></script> <script> function WebSocketAdapter(url){ this.ws=new WebSocket(url); this.ws.onmessage = function(evt) {$("#msg").append("<p>"+evt.data+"</p>");}; this.ws.onclose = function() { alert("socket cerrado"); }; this.ws.onopen = function() { alert("conectado..."); }; this.send=function(msg) {this.ws.send(msg);} } var ws; $(document).ready(function(){ ws=new WebSocketAdapter("ws://localhost:8080/"); }); </script> </head> <body> <form> Enviar al servidor: <input id="texto" type="text" value="hola mundo!"></input> <input id="enviar" type="button" value="enviar" onclick="ws.send($('#texto').val())"/> </form> <div id="msg"></div> </body></html>
Nuestro cliente<html> <head> <script src='jquery.min.js'></script> <script> function WebSocketAdapter(url){ this.ws=new WebSocket(url); this.ws.onmessage = function(evt) {$("#msg").append("<p>"+evt.data+"</p>");}; this.ws.onclose = function() { alert("socket cerrado"); }; this.ws.onopen = function() { alert("conectado..."); }; this.send=function(msg) {this.ws.send(msg);} } var ws; $(document).ready(function(){ ws=new WebSocketAdapter("ws://localhost:8080/"); }); </script> </head> <body> <form> Enviar al servidor: <input id="texto" type="text" value="hola mundo!"></input> <input id="enviar" type="button" value="enviar" onclick="ws.send($('#texto').val())"/> </form> <div id="msg"></div> </body></html>
Nuestro cliente<html> <head> <script src='jquery.min.js'></script> <script> function WebSocketAdapter(url){ this.ws=new WebSocket(url); this.ws.onmessage = function(evt) {$("#msg").append("<p>"+evt.data+"</p>");}; this.ws.onclose = function() { alert("socket cerrado"); }; this.ws.onopen = function() { alert("conectado..."); }; this.send=function(msg) {this.ws.send(msg);} } var ws; $(document).ready(function(){ ws=new WebSocketAdapter("ws://localhost:8080/"); }); </script> </head> <body> <form> Enviar al servidor: <input id="texto" type="text" value="hola mundo!"></input> <input id="enviar" type="button" value="enviar" onclick="ws.send($('#texto').val())"/> </form> <div id="msg"></div> </body></html>
Nuestro cliente<html> <head> <script src='jquery.min.js'></script> <script> function WebSocketAdapter(url){ this.ws=new WebSocket(url); this.ws.onmessage = function(evt) {$("#msg").append("<p>"+evt.data+"</p>");}; this.ws.onclose = function() { alert("socket cerrado"); }; this.ws.onopen = function() { alert("conectado..."); }; this.send=function(msg) {this.ws.send(msg);} } var ws; $(document).ready(function(){ ws=new WebSocketAdapter("ws://localhost:8080/"); }); </script> </head> <body> <form> Enviar al servidor: <input id="texto" type="text" value="hola mundo!"></input> <input id="enviar" type="button" value="enviar" onclick="ws.send($('#texto').val())"/> </form> <div id="msg"></div> </body></html>
Nuestro cliente<html> <head> <script src='jquery.min.js'></script> <script> function WebSocketAdapter(url){ this.ws=new WebSocket(url); this.ws.onmessage = function(evt) {$("#msg").append("<p>"+evt.data+"</p>");}; this.ws.onclose = function() { alert("socket cerrado"); }; this.ws.onopen = function() { alert("conectado..."); }; this.send=function(msg) {this.ws.send(msg);} } var ws; $(document).ready(function(){ ws=new WebSocketAdapter("ws://localhost:8080/"); }); </script> </head> <body> <form> Enviar al servidor: <input id="texto" type="text" value="hola mundo!"></input> <input id="enviar" type="button" value="enviar" onclick="ws.send($('#texto').val())"/> </form> <div id="msg"></div> </body></html>
Nuestro cliente<html> <head> <script src='jquery.min.js'></script> <script> function WebSocketAdapter(url){ this.ws=new WebSocket(url); this.ws.onmessage = function(evt) {$("#msg").append("<p>"+evt.data+"</p>");}; this.ws.onclose = function() { alert("socket cerrado"); }; this.ws.onopen = function() { alert("conectado..."); }; this.send=function(msg) {this.ws.send(msg);} } var ws; $(document).ready(function(){ ws=new WebSocketAdapter("ws://localhost:8080/"); }); </script> </head> <body> <form> Enviar al servidor: <input id="texto" type="text" value="hola mundo!"></input> <input id="enviar" type="button" value="enviar" onclick="ws.send($('#texto').val())"/> </form> <div id="msg"></div> </body></html>
Echo (single client)
require 'rubygems'require 'eventmachine-websocket'
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8080) do |con| con.on_open { con.send "Cliente conectado"} con.on_message { |msg| con.send msg.reverse } con.on_close { puts "Cliente desconectado" }end
Multichat en 23LOCrequire 'rubygems'require 'eventmachine-websocket'
connections=[]indexes={}
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8080) do |con|
con.on_open do indexes[con]=connections.size+1 con.send "<p class=\"highlight\">Eres el cliente #{indexes[con]}<p>" connections.each{ |c| c.send "<p class=\"highlight\">El cliente #{indexes[con]} ha entrado en la sala<p>" } connections << con end con.on_message do |msg| connections.each{ |c| c.send "<p><span class=\"cliente\">Cliente #{indexes[con]}:</span> #{msg}</p>" } end con.on_close do c.send "<p class=\"highlight\">Has abandonado la sala</p>" connections.delete con indexes.delete con endend
Conclusiones
• Hasta la aparición de HTML5, XMPP tenía unas expectativas muy altas como alternativa a Comet.
• Sin embargo, se han cancelado muchos servicios XMPP para el consumo de datos en tiempo real (Twitter firehose API)
•Websocket se presenta como una alternativa más simple y elegante para la implementación de servicios Web de tiempo real
• XMPP no pierde fuerza para mensajería instantánea
Bilbiografía
Gracias
CLOUD COMPUTING.DESARROLLO DE APLICACIONES Y
MINERÍA WEB
Miguel Fernández Fernández [email protected]
Programa de extensión universitariaUniversidad de Oviedo
Top Related