4.1. El paradigma base Client / Servidor
4.1.1. Paradigma base ()
4.1.2. Socket de Berkeley
4.1.3. Algorismes i qüestions al voltant del servidor () - ()
4.1.4. Algorismes i qüestions al voltant del client ()
4.2. Models de comunicació ()
4.3. Sistemes distribuïts ()
4.4. Nous paradigmes: codi mòbil i agents mòbils
4.4.1. Introducció als nous paradigmes ()
4.4.2. Codi Mòbil ()
4.4.3. Agents Mòbils ()
4.4.4. Aplicacions dels Agents Mòbils ()
4.4.5. Agents i seguretat
4.4.6. JADE/MARISM-A: agents mòbils segurs ()
4.4.7. Arquitectures d’Agents Mòbils ()
[28/05] ()
El paradigma base en el que es basa internet es el de client/servidor, es el més utilitzat per que aplicacions de diferents màquines interactuin i cooperin a través de la xarxa. Aquest tipus d'interacció, en general, es la base que s'utilitza per totes les comunicacions, i per les aplicacions distribuides que treballen a través d'internet cooperant amb altres aplicacions o màquines. Les dues parts d'aquest paradigma, són, detalladament:
Servidor: Es una aplicació que ofereix un servei, senzill o complexe, al que es pot accedir, o es pot utilitzar, a través de la xarxa. Es la part pasiva d'aquest mètode, ja que està esperant a que li arribin peticions i quan arriba una executa el servei i retorna el resultat.
Client: El client es el programa o aplicació que envia la petició al servei i espera la resposta, és, per tant, la part activa.
La interacció que hi ha entre el client i el servidor es sol anomenar peticició/resposta, pel fet de que fins que no hi ha una petició no passa res, i quan hi ha es genera i s'espera la resposta.
El servei que ofereixen els servidos pot estar a diferents servidors, que ofereixen el mateix servei, i poden estar a diversos hosts o al mateix. El servidor, comença la execució i va acceptant peticions i enviant respostes infinitament, en canvi, el client, acaba la seva execució després de haber fet un número finit de peticions de servei al servidor. El servidor accepta les peticions per un port conegut (well-known) que ha estat reservat pel servei que ofereix, en canvi, el client envia la petició per un por arbitrari, que no sigui utilitzat i que no estigui reservat.
Al paradigma client/servidor hi ha tres nivells diferenciats:
Nivell d'interficie: és el que permet la interacció amb l'usuari, o d'una aplicació amb una altre.
Nivell de processament: és el nucli de l'aplicació, és la part que opera amb les dades.
Nivell de dades: és on es fa el manteniment de les dades que usen i necessiten les aplicacions.
Normalment els clients tenen el nivell d'interficie i els servidors
tenen el de processament i el de dades. Però, no sempre es així,
depenent de l'aplicació es poden repartir els nivells de diferents
maneres, dividits, o amb altres nivells.
Arquitectures més modernes:
Three-tiered (a tres bandes): El servidor fa al mateix temps de client d'altres servidors, s'utilitza quan s'ha d'accedir a servidors de bases de dades, per exempla a una web de comerç electrònic.
Distribució Horitzontal: Els servidors estàn distribuits en diferents localitzacions per balancejar la càrrega.
Distribuició peer-to-peer: Els clients col·laboren entre ells simètricament, tots ofereixen els mateixos serveis, i fan alhora de client i de servidor, un exemple clar son els programes de compartir arxius com eMule.
[24/05] ()
Client i servidor estan a la capa d'aplicació. Els protocols d'extrem a extrem (UDP/TCP) estan a la capa d'operatiu.
Cal una interfície entre les dues capes que sigui universal i pugui ser utilitzada amb independència dels sistema operatiu.
Aquestes interficies han d'especificar:
Reserva de recursos
Establiment de connexions
Endpoints (punts d'accés, adreces)
Les interfícies estan poc especificades a nivell d'implementació. Existeixen diverses propostes:
Interfície SOCKET de BERKELEY. De BSD Unix. És la més present, a més del 90% de sistemes. GNU/Linux i M$-Windows l'utilitzen, per exemple.
XTI (X/Open Transport Interface). Abans TLI (Transport Layer Interface). De AT&T Unix.
Tots dos són similars en
el model de programació en xarxa, però amb primitives diferents.
Nosaltres només veurem el socket de Berkerley.
Conceptualment,
un socket és un punt d'accés de comunicació a través del qual una
aplicació pot enviar o rebre dades per una xarxa subjacent.
El conjunt de primitives per a l'utilització d'aquesta interfície no pertany al grup d'estàndards TCP/IP
El
desenvolupament original com a part del SO Unix ha fet que estigui
basat en el sistema d'accés a arxius i dispositius. Les seves
primitives son les mateixes que les d'arxius: open - read - write -
close.
Al crear un
socket se li assigna un descriptor, pel seu ús i per accedir-hi.
L'espai numèric per l'assignació dels descriptors es comparteix amb el
sistema de fitxers i dispositius.
Els sockets són més complexes: caldrà especificar molts més paràmetres i opcions.
Principals primitives bàsiques (system calls):
result = socket( pf, type, prot): Ens retorna
un descriptor de socket, el qual podrem utilitzar després per crides al
sistema. Si ens retorna -1, s'ha produït un error.
result: Descriptor que identificarà al socket.
pf: Familia de protocols (p.e. PF_INET: TCP/IP, PF_PUP: Xerox, PF_UNIX: Unix).
type: Tipus de comunicació:
SOCK_STREAM Servei orientat a connexió per flux.
SOCK_DGRAM Datagrames sense connexió.
SOCK_RAW Per accedir directament a la interfície.
prot: Protocol específic per la transmissió.
close( socket ): Decrementa el
comptador de referències associat al socket i tanca la connexió del
nostre descriptor de socket si arriba a zero. Si cridem a close() no es podrà escriure o llegir aquell socket, i si algú ho intenta rebrà un missatge d'error.
bind( socket, localaddr, addrlen ):
S'utilitza quan volem fer servir els ports locals de la nostra màquina
(usualment quan utilitzem la crida listen()). La seva funció esencial
és associar un socket amb un port de la nostra màquina. Igual que
socket(), retornarà -1 en cas d'error.
socket: Descriptor del socket.
localaddr: Endpoint local per associar al socket.
addrlen: Número de bytes del endpoint
connect( socket, destaddr, addrlen ):
S'utilitza per connectar-se a un port definit a una direcció IP. Si el
socket fa servir un servei sense connexió només s’utilitza per
enmagatzemar adreces. Retornarà -1 en cas d'error.
destaddr: Endpoint de l’adreça destí de la connexió.
addrlen: Número de bytes del endpoint
shutdown( socket, mode ): Tanca parcialment la connexió bidireccional. Si establim mode a 2 equival a fer un close()
mode: Quin sentit de la connexió es tanca.
send( sock, message, length, flags ): El propòsit d'aquesta funció es enviar dades utilitzant sockets de fluxe (TCP) o sockets connectats de datagrames (UDP amb connect() fet). Al igual que totes las altres crides, send() retorna -1 en cas d'error, o el nombre de bytes enviats en cas d'èxito.
message: Apuntador a les dades a enviar.
flags: Opcions pel control de la transmissió.
sendto( sock, message, length, flags, destaddr, addrlen ): Igual que send() però a mes accepta com a paràmetre un socket no connectat.
message: Apuntador a les dades a enviar.
flags: Opcions pel control de la transmissió.
destaddr: Punter a l’estructura amb l’adreça del destí.
addrlen: Longitud de l’adreça.
write( socket, buffer, length ):
Escriu dades a un socket connectat de manera anàloga a com ho faríem
amb un descriptor de fitxers. Retorna el nombre de bytes transmessos o
-1 en cas d'error.
buffer: Adreça on són les dades a enviar.
length: Número de bytes a enviar.
read( socket, buffer, length ):
Llegeix dades d'un socket connectat de manera anàloga a com ho faríem
amb un descriptor de fitxers. Retorna el nombre de bytes llegits o -1
en cas d'error.
buffer: Adreça on es desen les dades rebudes.
length: Número de bytes a llegir.
recv( sock, buffer, length, flags ): Al igual que es va dir per send(), aquesta funció s'utilitza amb sockets de fluxe o sockets connectats de datagrames. Igualment que send(), recv() retorna el nombre de bytes llegits al buffer, o -1 si es produeix un error.
flags: Pel control de la recepció. Exemple: opció per poder veure les dades rebudes sense treure-les del buffer.
recvfrom( sock, buffer, length, flags, fromaddr, addrlen ): Igual que recv() però a mes accepta com a paràmetre un socket no connectat.
fromaddr: Adreça d’on venen les dades.
addrlen: Longitud de l’adreça.
listen( socket, qlength ):
S'utilitza si s'estàn esperant connexions entrants, que es el mateix
que dir que estem esperant que algú es connecti a la nostra màquina.
Prepara el socket per a rebre connexions. Només s’aplica als sockets
orientats a flux.
qlength: Longitud de la cua de peticions.
newsock = accept( socket, addr, addrlen ): Quan quelcom vol connectar-se a la nostra màquina hem d'utilitzar accept() per conseguir la connexió. Quelcom sols podrà connectar-se (connect()) a la nostra màquina si nosaltres acceptem (accept()).
addr: Adreça del client que fa la petició.
newsock: Nou socket que crea el sistema i que es queda connectat amb el client.
nready = select( ndesc, indesc, outdesc, excdesc, timeout ): Permet escoltar un o varis sockets però amb condicions de tmeout, per no bloquejar indefindament un programa.
nready: Número de descriptors que estan preparats.
ndesc: Número de descriptors a examinar.
indesc, outdesc, escdesc: Punter a una màscara de bits que especifiquen els descriptors a mirar per entrada, sortida, o condicions d’excepció.
timeout: Temps a esperar que arribin dades. Si és zero s’espera indefinidament.
Principals funcions de biblioteca relacionades:
getpeername(socket,destaddr,addrlen):: Agafa l'adreça de destinació d'un socket
getsockname(socket,localaddr,addrlen): Agafa l'adreça d' orígen (local) d'un socket
getsockopt(soc,level,optid,optval,length):: Per a obtenir informació de les opcions d'un socket.
setsockopt(soc,level,optid,optval,length): Per a modificar les opcions d'un socket.
gethostbyname(namestr): Obté l’adreça d’un host a partir del nom.
struct hostent *gethostbyaddr(const char *addr, int len, int type): Devuelve una estructura del tipo hostent para la dirección de anfitrión dada addr de longitud len y de tipo type. El único tipo de dirección válido actualmente es AF_INET.
getprotobyname(name): Ens ofereix informació d’un protocol a partir del seu nom.
getprotobynumber(number): Ens ofereix la mateixa informació, però a partir del número identificador.
getservbyname(name,proto): Per a obtenir informació d’un servei a partir del nom.
getservbyport(port,proto): Exactament el mateix que l’anterior però a partir del número de port associat.
Les funcions de biblioteca estan al mateix nivell que les aplicacions d'usuari.
Fonts:
Apunts de classe.
http://es.tldp.org/Tutoriales/PROG-SOCKETS/prog-sockets.html
Manual de Linux
[24/05] ()
En les apliacions client-servidor hi ha tres paràmetres que definieixen el comportament d'aquestes aplicacions.Aquests paràmetres són:
Model iteratiu / concurrent: Un model interatiu les peticions s'atenen seqüencialment, és a dir, la primera petició que arriba, al servidor o client, és atesa en primer lloc, la segona en segon lloc i així successivament. Normalment els servidors són iteratius. En canvi els clients no ho són. Els clients normalment són concurrents. Un model concurrent el que fa és atendre en el mateix temps peticions diferents. Aquesta concurrencia es pot dur a terme per replicació de processos (el pare crea els fills on el codi esta en processos diferents) o en un únic procés (el pare i els dills comparteixen codi, encara que el pare executarà una part del codi i els fills una altra).
Fiabilitat en l’aplicació / en el protocol de transport: Pel que fa la fiabilitat el protocol TCP, com per exemple un servidor http, ja ens ofereix fiabilitat per tant totes les aplicacions que corren sobre TCP no es necessari implementar la fiabilitat. En el cas del protocol UDP no posseeix mecanismes per a la fiabilitat,com per exemple un servidor TFTP, per tant si una aplicaicó requereix de fiabilitat usant UDP, s'hauria d'implmentar aquesta fiabilitat peró implementarla usant UDP és complicat. Per això normalment no s'utilitza UDP quan es requereix fiabilitat.
Informació que tenen els seridors sobre els clients amb estat / sense estat: Segons les transparències de l'assignatura:
Un servidor amb estat és aquell que necessita enmagatzemar informació relativa a la connexió per tal d’oferir respostes a un client.
Un servidor sense estat, o stateless, és aquell que no necessita informació de peticions prèvies d’un client per a oferir-li una resposta.
Sabent aquestes definicions el
servidor amb estat té en tot moment controlada la petició de resposta
al client. En canvi si és un servidor stateless, rl client és
l'encarregat d'informar sobre la petició cada vegada que en llenci una.
En el cas d'un server de fitxers podem diferenciar dos algorismes per si es amb o sense estat. Si el servidor es amb estat l'algoritme te 4 pasos on el 3r i el 4t es repeteixen fins haber enviat l'arxiu. Els pasos són els següents:
CLIENT TO SERVER envia una petició de lectura d'un fitxer.
SERVER TO CLIENT el servidor crea una entrada en la taula d'estats amb l'estat del client
CLIENT TO SERVER fa la demanda de llegir n bytes
SERVER TO CLIENT el servidor envia els bytes sol.licitats i situa el cursor sobre el fitxer en l'estat que te el client.
Aquests servidors generen problemes, per exemple si es caiguès o es reiniciès el servidor les lectures dels fitxers es perderien, si en lloc de caure el servidor es caiguès el client la entrada de la taula seria erronia. A més a més si no hi hagués fiabilitat i arribessin peticions repetides les respostes podrien ser diferents. Per això els servidors sense fiabilitat, TFTP, solent tenir estats i els que són fiables no en tenen, HTTP. Si el servidor es stateless l'algorisme té un parell d'estats menys que s'aniran repetint fins que la voluntat del client ho decideixi. L'algorisme és el següent:
CLIENT TO SERVER envia la petició de lecutra del fitxer especificant el nom del fitxer, la posició del fitxer on vol adquirir els bytes i la cantitat de bytes que vol adquirir.
SERVER TO CLIENT li envia la informació solicitada i es despreocupa d'aquest clinet.
FONTS:
Trasparències de classe
()
Podem tenir diferents tipus de servidors combinant aquestes dos caracteristiques:
. |
TCP(conexio) |
UDP(sense conexio) |
Iteratiu |
Cas extrany |
Habitual |
Concurrent |
Habitual |
No te sentit: Tg >> Ts |
Ts -> Temps de servei de cada peticio.
Tg -> Temps de gestio de cada peticio.
Servidor Iteratiu sense conexió
En el cas Tg=0
Algorisme:
1.Crea un socket i l'asocia ("Bind") a un número de port i un numero IP local.
2.Repetidament llegeix una peticio del cliente i formula una resposta.
Per a acceptar una peticio s'utilitza la crida al sistema
"Recvfrom" a partir de la qual s'obte la direccio de la maquina remota.
Per a respondre a una peticio s'utilitza "sendto"
Crides al sistema utilitzades:
//creacio del socket
sock= socket(PF_INET, SOCK_DGRAM, PROT_UDP)
//Asociacio del socket al port
bind(sock, ads)
//ads -> sockaddr_in
// adreça=INADDR_ANY
// port=port de serevei
do {
recvfrom(sock, buffer, adreça_client)
sendto(sock, missatge, adreça_client)
} while (no acabem)
Servidor iteratiu amb conexio
Aqui utilitzarem dos sockets. Un estarà esperant les conexions mentres l'altre servirà les peticions.
Algorisme:
Crea un socket i l'asocia ("Bind") a un numero de port i un numero Ip local
-La constant “INADDR_ANY” especifica que el servidor gateway pot acceptar dades en qualsevol de les seves adreces IP.
El socket queda en mode pasiu esperant peticions ("Listen")
Accepta una conexió i obté un nou socket per a atendre aquesta petició.
Repetidament llegeix una petició del client i formula una resposta enviant-la d'acord al
protocol.
Quan acaba amb un client particular tanca la conexió i torna a acceptar una nova conexió.
Crides al sistema utilitzades:
msock = socket(PF_INET, SOCK_STREAM, PROT_TCP)
bind( msock, ads)
// ads -> sockaddr_in
// adreça=INADDR_ANY
// port=port de servei
listen=( msock, long_cua_espera)
ssock = accept ( msock )
do {read(ssock, ...)
write(ssock, ...)
} while (no acabem)
close (ssock)
Servidor Iteratiu amb Pseudoconexions
En aquest cas pasem a utilitzar dos sockets amb tres estructures sockaddr_in. El protocol utilitzat es UDP.
Algorisme:
Crear un socket (msock) i vincular-lo a una adreça/port
Llegir petició.
Crear un socket de servei ssock i vincular-lo a una adreça/port
Repetir {Enviar pel socket (resposta)}; Llegir des del socket(Peticio)
Tancar el socket ssock.
Retornar a 2.
Crides al sistema utilitzades:
msock=socket(PF_INET, SOCK_DGRAM, PROT_UDP)
bind( msock, speticio )
recvfrom( msock, peticio, client)
ssock = socket(PF_INET, SOCK_DGRAM, PROT_UDP)
bind( ssock, sservei)
// sservei -> adreça = INADDR_ANT
// puerto=0
do { sendto (ssock, resposta, sclient)
recvfrom (ssock, buffer, sclient)
} while (no acabem)
close(ssock)
Servidor concurrent amb conexions
El servidor pot processar mes d'una peticio de client de manera simultanea.
Tot i que teoricament podrian processarse totes les peticions a la vegada, existeix un petit retras al crear el proces (Tg).
Un servidor concurrent per a la creacio de processos es justifica si:
Tenim un sistema multi-processador -> Un proces servidor en cada processador.
El Ts es mes gran que el Tg. (Ts > Tg)
Els temps de servei son molt variables (alguns molt petits i altres molt grans).
En aquest tipus de servidors tindrem un servidor Master i altres Slaves.
Algorisme:
1. Crea un socket i l'asocia ("Bind") a un numero de port i un numero IP local
2. El socket queda en modo pasiu esperant peticions ("Listen")
3. Repetidament crida a "Accept" per a rebre peticions de clients i crear un proces fill (esclau) per a processar cada petició.
El proces fill rep la peticio.
Interactúa amb el client a traves de la conexió ("Read", "Write").
El fill tanca finalment la conexió.
Crides a sistema utilitzades:
//MASTER (pare)
msock=socket(PF_INET, SOCK_STREAM, PROT_TCP)
bind(msock, ads)
listen(msock, long_cua_espera)
do{ ssock = accept (msock)
crear_slave
} while (sempre)
//SLAVE (fill)
do {read (ssock, ...)
write (ssock, ...)
} while (no acabem)
close (ssock)
El proces pare ha d'estar pendent de que el proces fill mori
El fill, al morir, envia una senyal al pare (senyal SIGCHLD)
El pare te que donar el vist i plau, sino el fill quedaria zombi.
Una forma de millorar l'eficiencia es crear de manera anticipada els processos slave. Quan arriben peticions s'asignen al primer proces slave lliure.
Servidor concurrent de proces unic amb conexions.
En aquest tipus de servidor nomes existeix un proces que serveix totes les peticions dels clients concurrentement. Aquest tipus de servidor es util quan hi ha molts clients que demanen el mateix. Si hi ha molta activitat per part dels clients, el rendiment del servidor cau rapidament. S'utilitza la primitiva SELECT per a detectar l'activitat d'algun socket. Aquesta primitiva retorna 1 si hi ha hagut activitat o 0 si ha caducat el temps d'espera.
SELECT System Call int select(int nfds, fd_set *readfds,fd_set *writefds, fd_set *exfds, struct timeval *timeout)
-La crida al sistema select
permet que un proces d'usuari ordeni al kernel que esperi que es
produeixin operacions d'E/S sobre un conjunt de descriptors de fitxers
i avisi al proces quan un d'aquests events succeeixi.
-FD_SET es una estructura de bits, o màscara que identifica (mapeja) un conjunt de descriptors de fitxers.
-Select
retorna el descriptor de fitxer en el que es produeixen operacions
d'E/S; "0" si es supera un límit de temps i -1 si es produeix un error.
-Si el paràmetre de timeout es nul s'espera indefinidament fins que es produeixi una operació d'E/S.
Macros per controlar la llista de sockets (estructura FD_SET):
FD_ZERO(fd_set *fdset) inicialitza la màscara fdset
FD_SET(int fd, fd_set *fdset) : Afegeix el descriptor fd al conjunt fdset
FD_CLR(int fd, fd_set *fdset) : Borra el descriptor fd del conjunt fdset
FD_ISSET(int fd, fd_set *fdset) : Testeja si sobre el descriptor fd s'ha produit una operacio d'E/S
Algorisme:
Crea un socket i l'asocia ("Bind") a un numero de port i un numero Ip local.
Utilitzacio de "select" per esperar operacions d'E/S en els sockets existents.
Si es detecta una conexió en el socket original es fa una
trucada a "Accept", es crea un nou socket i s'afegeix aquest a la
llista de sockets que testeja "select".
Si es detectan peticions en els sockets diferents de l'original
s'utilitzaran les trucades "Read" per llgir la petició i "Write" per
enviar la resposta.
Trucades al sistema utilitzades:
msock=socket(...);
bind(...);
listen(...)
FD_ZERO( llista );
FD_SET( msock, lista )
do {ret = select (..., llista , ...)
if FD_ISSET (msock, llista){
ssock= accept (msock);
FD_SET (ssock, llista)}
for i in lista {
if FD_ISSET (i, llista){
read( ssock); write( ssock) }
if fi_servei(i){
close(ssock); FD_CLEAR(ssock,...)
}}} while (sempre)
Superservidors
Podem diferenciar entre servidors stand-alone i superservidors.
Els servidors stand-alone ofereixen un servei per un determinat port. Els superservidors son servidors que atenen peticions de molts ports al mateix temps. Quan arriba una peticio al superservidor, aquest posa en funcionament un servidor concret i li passa la conexio. D'aquesta manera s'estalvien recursos. Exemple: Internet daemon (inetd): echo, telnet, ftp, finger....
FONTS:
Trasparències de classe
http://pegaso.ls.fi.upm.es/
()
[24/05] ()
Com hem explicat en l'inici del punt anterior un client ha de tenir un model interatiu. Aquests models per als clients poden ser amb connexió (quan es treballa sobre TCP) o sense conexió (quan es treballa sobre UDP), el qual necessita una fiabilitat relativa proporcionada per l'aplicació.Aquest model de connexió s'usa quan hi ha una relació curta i sense justificació de connexió. L'algorisme a utilitzar per als clients iteratius sense connexió el que primer ha de fer es trobar la IP i el port del servidor (normalment concurrent) al que s'ha de connectar. Un cop te aquesta informació el client crea el socket i l'associa a la inforamció anteriorment trobada, es a dir, l'associa a la IP local i al port lliure. Un cop hem seguit fet aquests passos, s'enviarà la petició pel socket i es llegirà la resposta des del socket repetidament fins arribar al final del protocol de l'aplicació. Les crides utilitzades les mostren en el segúent fragment de codi:
sock=socket(PF_INET,SOCK_DGRAM,PROT_UDP)
bind(sock,adreça_local,...) // port=0 !
do {
sendto(sock,missatge,...,adreça_remota)
recvfrom(sock,missatge,...,adreça_remota)
} while (no acabem)
close(sock)
Una altra opció és utilitzar el mateix algorisme pero una crida adicional. Aquest crida al sistema es la connect, en lloc de bind la qual no fa la connexió (SYN,SYN/ACK,ACK) en si, sinó serveix per emmagatzemar les adreces. El que si que ens facilita es a la hora de enviar la petició i rebre la resposta, ja que no es necessari introduir en la crida al sistema (recv/send) les adreces remotes. El codi es el següent:
sock=socket(PF_INET,SOCK_DGRAM,PROT_UDP)
connect( sock, adreça_remota )
do {
sendto(sock,missatge)
recvfrom(sock,missatge)
} while (no acabem)
close(sock)
Per l'altra banda un client interatiu amb connexió
ha de tenir fiabilitat absoluta la qual es proporcionada en la capa de
transport, com bé hem dit abans un exemple és el protocol TCP. Aquest
model de connexió s'utilitza quan hi ha una relació duradera. Els
datagrames utilitazats per a la relació són 3 datagrames per a la
connexió i 4 datagrames per a la desconnexió.
L'algorisme
a utilitzar per als clients iteratius orientat a connexió serà el
mateix amb la única diferencia que en aquest cas després de crear el
socket el connectarem directament amb el servidor, en lloc d'associar
la IP i el port lliure com fem en el cas de clients interatius sense
connexió.
Les crides utilitzades les mostren en el segúent fragment de codi:
sock=socket(PF_INET,SOCK_STREAM,PROT_TCP)
connect( sock, adreça_remota, ...)
do { write( sock, buffer, longitud)
nb = read( sock, buffer, longitud )
} while (no acabem)
shutdown( sock, direcció )
close(sock)
on amb connect és fa el protocol d'establiment de la connexió.
FONTS:
http://www.wkipedia.org
Trasparències de classe
index
[25/05] ()
Se trataran 4 modelos de comunicación porque la comunicación de los partes dentro de una aplicación distribuida es muy importante. Existen la RPC (Llamada a Procedimiento Remoto), la RMI (Invocación Remota de Métodos), la MOM (comunicación/middleware orientada a mensajes) y los Streams (flujos). Para hacer la comunicación más cómoda y transparente se usan aplicaciones "middleware". Se encuentran en la capa de aplicación (del modelo TCP) y ofrecen servicios como la autentificación, la exclusión mutua para aplicaciones distribuidas y componentes distribuidos.
RPC
Se trata de llamadas de procedimientos que se encuentran en diferentes máquinas. Hay tres pasos:
Un proceso en una máquina (cliente) en algún parte de su código llama a un proceso de una máquina remota (servidor).
El proceso del cliente se suspende y el proceso del servidor está inicializado.
El resultado del proceso remoto se envía al cliente que ahora puede seguir la ejecución del proceso original.
La llamada a otra máquina se realiza de manera transparente para la máquina original. Para esto existen los stubs en ambos extremos. Se pueden crear a mano, pero existen generadores que fabriquen un stub para un proceso. Una máquina que quiere ejecutar métodos remotos puede acceder un directorio que tiene información sobre los procesos disponibles para RPC.
En muchos sistemas UNIX-like este directorio se puede llamar la herramienta portmap para acceder este directorio. Además existe "rpcgen" para generar un stub y "rpcinfo" para obtener información de los programas.
Junto a este modelo existen otros más complejos: Existe el modelo Doors que es utiliza para la comunicación entre procesos dentro de una misma máquina. En el modelo RPC asíncrono el proceso del cliente no se bloquea mientras se ejecuta el método remoto del servidor. La respuesta se recibe de forma asíncrona.
RMI
RMI es una evolución de RPC. Se usa para entornos orientados a objetos. Funciona así:
El cliente utiliza una interfaz para acceder a un objeto remoto del servidor.
El servidor recibe esta petición del cliente a través de un interfaz que accede a un objeto local para llamar a un método. El objeto tiene un estado.
El resultado se reenvía al cliente.
En este escenario un stub o proxy (por parte del cliente) y un skeleton (por parte del servidor) se encargan de la encapsulación de la comunicación entre cliente y servidor.
Es sistema RMI se aplica en lenguajes OO como Java y C++. Tanto como en RPC existe un directorio conteniendo información sobre los objetos disponibles para la invocación remota. En java esto hace la rmiregistry. Los stubs y skeletons se generan a través el programa rmic.
MOM
RPC y RMI son orientados a aplicaciones y por eso necesitan una sincronización fuerte entre el cliente y el servidor. En algunos ocasiones no se puede garantizar. Se aplica otro mecanismo que es orientado a mensajes: La MOM.
Se realiza de manera asíncrona, es decir, el cliente - después de dirigir una petición al servidor mediante un mensaje - no espera sino sigue ejecutándose. Otra propiedad de la MOM es la persistencia de la comunicación. Hay una cola de espera para guardar los mensajes que se quieren enviar. Así los mensajes no se pierden. Se aplica por ejemplo a los correos electrónicos.
Otros particularidades de sistemas basados en mensajes son la garantía que un mensaje llegará a la cola de entrada del receptor, la garantía de guardar un cierto número de mensajes durante un tiempo y la posibilidad que el emisor o receptor puedan ser inactivos durante la transmisión de los mensajes.
Pensamos en un escenario donde una máquina quiere enviar un mensaje a otra. Son conectados a través de varios routers. Todas estas máquinas tienen una cola de entrada y una de salida. Entonces los pasos para enviar un mensajes son los siguientes:
Cuando el emisor quiere enviar un mensaje, primero lo pone en su cola de salida.
De esta cola el mensaje se pasa a la cola de entrada del primer router.
Se pasa a la cola de salida del primer router.
Lo mismo pasa con el segundo, tercero,... router.
Al final llega a la cola de entrada del receptor.
El receptor procesa el mensaje y crea una respuesta.
Luego pone la respuesta en su cola de salida.
La respuesta viaja de la misma manera que el mensaje original hacia el emisor.
Streams
Los tres ejemplos anteriores todos son basados en el intercambio de unidades independientes de comunicación. Pero existen aplicaciones que usan flujos ("streams") porque tienen que enviar información constantemente.
Podemos clasificar los flujos en tres tipos:
Síncrono: Hay un tiempo establecido entre dos elementos de flujo.
Asíncrono: El tiempo entre dos elementos del flujo no importa.
Isocrono: Existe un tiempo mínimo y máximo entre dos elementos del flujo. Para asegurar el isocronismo se aplican mecanismos d sincronización y de garantia de la calidad de servicio ("Quality of Service"). Se usa en sistemas multimedia distribuidos.
Fuentes:
http://es.wikipedia.org (varias páginas)
transparencias de la asignatura
()
Un sistema distribuït és aquell que a l’hora d’obtenir un resultat utilitza vàries màquines que col•laboren entre elles, gestionant una sèrie de recusos compartits entre elles, treballant de manera concurrent, utilitzant un esquema de comunicació client-servidor entre els diferents processos. Aquestes màquines interconnectades intercanvien missatges i es coordinen per l’execució d’una certa tasca.
En aquest escenari, per poder organitzar aquests sistemes ens serà de gran ajuda la utilització d’ objectes. Els avantatges dels models orientats a objectes (que aporten transparència i permeten treballar de manera unificada en xarxes heterogènees), sumats a la simplicitat i efectivitat de la comunicació client-servidor, formen sistemes distribuïts que poden ser implementats en multitut d’entorns diferents.
Explicarem alguns d’aquests sistemes distribuits basats en objectes:
CORBA de OMG:
El Common Object Request Broker Architecture creat per Object Management Group és un model específic de sistema distribuït que permet desenvolupar aplicacions distribuïdes orientades a objectes amb facilitat, aplicacions que interactuen sense importar el llenguatge ni la màquina en la que s’ha implementat.
El seu funcionament es basa en l’existència d’un missatger que és l’encarregat de enviar les sol•licituds entre els diferents objectes. El missatger anomenat ORB (Object Request Broker) és la base del sistema CORBA ja que és el que proporciona la comunicació entre els diferents grups d’elements. Si els diferents sistemes CORBA tenen el mateix ORB, poden operar entre ells, però si no el tenen, hauran d’utilitzar GIOP (General Inter-Orb Protocol). Si GIOP s’aplica sota TCP, s’anomena IIOP (Internet Inter-ORB Protocol). Aquests protocols s’encarreguen d’ executar els mètodes i les funcions dels objectes del sistema.
Els elements a comunicar son els següents:
- Objectes d’aplicació: implementen interfícies i es comuniquen entre si mitjançant l’ORB
- Serveis verticals: serveis comuns per a un domini concret
- Serveis horitzontals: col.lecció d’objectes prefabricats
- Serveis comuns d’objectes: necesaris per la construcció d’aplicacions.
El llenguatge que utilitza CORBA per a qualsevol desenvolupament és l IDL (Interface Definition Language). Defineix els objectes, estructures i serveis que després seran utilitzats.
Exemple de creació d’una interfície “Saludos”.
module unejemplo {
interface Saludos {
string decirHola();
};
};
GLOBE:
El Global Object-Based Environment es un altre model de sistemes distribuïts orientat a objectes, però a diferencia de CORBA, està orientat a englobar un gran numero d’usuaris i objectes.
El funcionament de GLOBE es basa en la creació d’un espai de memòria compartida de gran abast a nivell d’aplicacions, espai que resideix en múltiples màquines i accessible pels diferents processos mitjançant la invocació dels seus mètodes.
Fonts:
http://www.osmosislatina.com/java/rmi.htm
http://www.itlp.edu.mx/publica/revistas/revista_isc/anteriores/dic98/cobjdist.html
http://www.monografias.com/trabajos16/componentes/componentes.shtml
apunts de classe
()
Al parlar de sistemes distribuïts, ens trobem que sovint necessitem que certs processos puguin “saltar” d’una màquina a una altra per a determinades aplicacions distribuïdes.
Malgrat que aquesta mobilitat de processos produeixi consum de recursos i actualment presenti algun que altre problema de seguretat, també ens proporciona una serie d’avantatges molt interessants:
Reducció de la carrega de xarxa
Adaptació dinàmica
Tolerància a fallides
Escalabilitat
Rendiment
...
Passarem a explicar els dos paradigmes dels que parlem:
Codi mòbil: És el codi del procés el que “salta” d’una màquina a una altre màquina remota i continua amb la seva execució de manera remota.
Agents software mòbil: és l’agent el que “salta”. El cos de l’agent conté el codi a executar. L’agent decideix quines accions ha de pendre.
FONTS:
apunts de classe.
index
[29/05] ()
El codi mòbil es un sistema que serveix per simplificar molt la programació d'un sistema distribuït. Raons per usar un codi mòbil:
Moure processos d’una màquina carregada a una altra menys carregada.
Minimitzar les comunicacions (moure el codi a les dades, en comptes de les dades al codi).
Realitzar processament local en el client abans d’enviar les dades.
Serveix per paral.lelitzar tasques.
Flexibilitat (decisió d’on poden ser executades diferents parts d’una aplicació distribuïda, per exemple).
Configuració dinàmica.
Descàrrega de codi al client.
Recàrrega dinàmica de component d’aplicacions distribuïdes.
El codi mòbil també te desaventatges, el mes notable és la seguretat.
Alguns exempes de codi mòbil són:
El postscript per imprimir a una impresora làser.
Els virus.
Els applets de java (malgrat que és un exemple una mica dolent perquè la comuincació es inictiada pel receptor)
Models de migració:
Migració Forta: El codi mòbil canvia d'estat (funciona igual que una màquina d'estats), i actua diferent segons en l'estat en el que es troba, amb migració forta l’estat de la execució és recuperat després de la migració, realment, l'estat es mou amb el codi.
Migració Feble: Només es el codi de l'aplicació el que es desplaça, l'estat de l'execució es perd en el procés de migració.
La migració forta és dificil d’implementar, calen mecanismes de baix nivell per a la recuperació de l’estat, a més, si es vol portabilitat també cal que aquests mecanismes siguin estàndard (que siguin iguals per tots els SO's).
És possible emular la migració forta utilitzant la feble? Sí, Ho ha de fer el programador, per exemple, es pot fer un codi que sigui com un autòmat (com una màuina d'estats), i crear un atribut del codi (de la classe) que serveixi per guardar l'estat.
Es pot distingir també entre dos tipus de migració: Iniciada per l’emissor i Iniciada pel receptor (Applets de Java o de Flash).
Els codis mòbils també es
poden clonar. Abans de ser llençat a una altra màquina es pot fer un
clon de l'aplicació i només llençar una de les dues aplicacions.
FONTS:
Transparències i apunts de classe.
index
[29/05] ()
Un Agent Mòbil és un procés que actua en representació d’algú (és un procés que, independentment de la màquina que estigui pertany a la màquina qui l'ha llençat), té les següents propietats:
És autònom: Una vegada llençat no cal que se li donin més paràmetres, actua per compte propi i pren decissions.
És reactiu: Segons l'entorn i els canvis que es produeixen en aquest l'agent pot respondre d'una manera o d'altre.
És proactiu: L'agent pot iniciar accions que afectin a l'entorn i que produeixen canvis a l'agència.
És comunicatiu : L'agent pot intercaviar informació amb altes agents, amb l'agència o amb usuaris.
És mòbil: Pot migrar a altres entorns d’execució.
Els agents mòbils tenen tots els aventatges dels codis mòbils, però a més d'aquests també poden:
Delegar tasques.
Accedir a recursos mentre l’usuari està off-line.
Fer computació distribuïda complexa.
Col.labrar amb altres agents.
Tenen la capacitat d’aprenendre i d'adaptar-se (prenen accions diferents depenent de l'entorn).
Executar-se asincronament en múltiples hosts.
Poden actuar amb falles de la xarxa, poden operar malgrat que no hi hagi connexió entre el client i el servidor.
El seu manteniment és flexible, si es vol que canviin les seves accions només s'ha de canviar el seu codi font.
Hi ha més tipus d’agents, que incorporen altres característiques, com per exemple agents d’informació, agents d’interficie ...
Un agent, per poder executar-se, necessita una Agència, les agències son entorns d'execució que hi ha a cada màquina per oferir uns serveis estàndard als agents, quan l'agent arriba a l'agència es comunica amb ella i decideix les accions que ha de fer a la màquina. Les agències permeten l'execució, la comunicació i la migració d'agents.
Estàndards
L'estandard més utilitzat que regula els diferents aspectes dels agents i de les agències es FIPA (Foundation for Intelligent Physical Agents). L’estandard més utilitzat que regula diferents aspectes dels agents i de les agències, i que desde el 2005 forma part del IEEE.
En que consisteix:
Estableix els components bàsics i el funcionament de diversos elements de les agències, per a permetre la interoperatibilitat, i la interacció entre agents i els sistemes basats en agents.
Defineix el llenguatge de comunicació dels agents, concretament l'ACL (Agent Communication Language).
La plataforma Jade, que utilitzem a les pràctiques de l'assignatura segueix aquest estàndard.
Components bàsics dels agents mòbils
Codi:
Codi comú per totes les agències.
Codi específic per a cada agència.
Dades:
Dades globals.
Dades específiques per a cada agència.
Itinerari:
Implicit, dintre del codi.
Explícit, estructura que contindrà la ruta que seguirà l’agent
FONTS:
Transparències i apunts de classe.
en.wikipedia.org
index
[29/05] ()
Algunes de les aplicacions més comunes son:
Monitorització, descobriment, i disponibilitat de recursos.
Recuperació de dades (per exemple les aplicacions Mar-de-Dades).
Administrar la xarxa.
Desplegament dinàmic de software. (GRIDs)
Hi ha aplicacions que només es poden realitzar amb agents mòbils, per exemple les aplicacions "MAr-de-Dades", aquestes aplicacions tenen les següents característiques:
L’execució requereix l’accés de gran quantitat d’informació distribuïda en una xarxa.
Les dades no poden abandonar el lloc d’origen (limitacions d’amplada de banda, restriccions legals, etc.).
Accés off-line dels recursos (l’usuari no està connectat constantment).
Exemples d'aplicacions de Mar-de-Dades
Detecció d’intrusos i d’atacs distribuïts (IDS).
Entrenament d’algorismes de classificació per a imatges mèdiques, per exemple, per classificar radiografies amb càncer o no mitjançant un mètode d'entrenament i aprenentatge, l'agent aniria d'hospital en hospitat visualitzant i entrenant-se amb les dades, però sense treure les imatges de l'hospital perque son dades privades, i podria agafar informació d'hospitals de tot el món fins ser un programa molt efectiu (imatge inferior).
Anàlisi conjunt d’imatges hiperespectrals distribuides en diferents centres.
Mineria de dades sobre fitxers de registre.
Les aplicacions Mar-de-Dades també permeten la
implementació d’esquemes complexes de seguretat per a oferir solucions
escalables en aplicacions com votacions electròniques, computació GRID
o subhastes en mercats electrònics.
FONTS:
Transparències i apunts de classe.
[25/05] ()
Els principals atacs es basen en substitució, denegació de servei, repudi, infiltració i accès no autoritzat.
La seguretat és un aspecte clau en els agents mòbils.Aquesta és una classificació dels possibles atacs.
Agent / Agència. L’agència pot limitar l’entorn d’execució (model Sandbox).
Agent / Agent. Mecanismes bàsics a les agencies eviten aquest tipus d’atacs.
Agència / Agència. És fàcil posar mecanismes per protegir les agències d’aquests atacs.
Agència / Agent. Difícil de solucionar, Els
agents depenen totalment de l’entorn d’execució. Alguns atacs d’aquest
tipus es poden evitar, altres són encara un problema obert.
Exemples d'atacs:
Manipulació o espiat de dades o codi
Denegació d’execució o falsa execució
Impersonació d’agència
Manipulació o espiat de les comunicacions
Re-execució
Manipulació de l’itinerari
Ampliació del tema (en anglés): ma_security.pdf
index
()
JADE/MARISMA (Architecture for Mobile Agents with Recursive Itinerary and Secure Migration) és un entorn per a l’execució d’agents mòbils desenvolupat a partir de JADE, que proporciona mecanismes de seguretat per a protegir els seus agents.
La seva importància resideix en que és el primer software de codi lliure que combina migració, mecanismes de protecció d’itineraris, codi i dades en lexecució d’agents.
Els següents softwares ja existien abans, però no compilen tots els requisits anteriors:
FIPA/OS: Es una plataforma de codi lliure que ajuda a la programació d’agents i sistemes multiagent heterogenis i que segueix l’estandard FIPA(Fundation for Intelligent Physical Agents). La seva llicència és restrictiva i no té agents mòbils.
Grasshopper:Eina multiagent, amb codi que té propietari i no es troba disponible. Finalment s’ha adaptat a l’estàndard FIPA.
JADE (Java Agent DEvelopement Framework): Software lliure per al desenvolupament d’ aplicacions basades en agents, per a sistemes que interaccionen. També segueix l’estàndard FIPA, però no suporta mobilitat. La seva llicencia és LGPL (Lesser General Public License, que permet enllaçar biblioteques lliures amb programes propietaris, amb una alta capacitat d’integració.
Elements que integren MARISMA
Agències
Agents Mòbils
Servei de directori i infraestructures de seguretat
Entorn de Desenvolupament Integrat
Com hem dit abans, JADE/MARISM-A incorpora en el seu entorn una eina de creació d’itineraris per als agents, que inclou programació orientada a agencia amb capacitat de soportar diferents arquitectures, eines criptogràfiques per protegir els agents i RAD (desenvolupament ràpid d’aplicacions).
Característiques de JADE/MARISM-A
Programat en JAVA en la seva totalitat (amb el que això implica(lliure, flexible, portàtil, ...)
Mecanismes de reflexió de JAVA per a la migració dels agents.
Utilitza missatges ACL(Agent Comunication Language) de FIPA per a la migració, sobre algun protocol de transmissió de missatges.
Serveis criptogràfics de protecció.
Agencies lleugeres en front d’agents autocontinguts.
Fonts:
http://pulsar.unizar.es/gluz/manual-sl/x505.html
http://usuario.cicese.mx/~mjuarez/articulo.pdf
apunts de classe
[25/05] ()
Les arquitectures dels agents mòbils ajuden a trencar el lligam del programador amb les tasques crítiques que tenen aquests agents com són la protecció i la migració.L'arquitectura d'un agent mòbil està formada per un codi, unes dades, un itinerari, els quals formen part de l'estructura de l'agent. Els itineraris n'hi han de dos tipus, els implícits i els explícits. L'itinerari implícit esta dins del codi al contrari dels itineraris explícitsels quals tenen una estructura separada del codi. Un itinerari explícit aproximadament és basa en la combinació recursiva de seqüències (tots els sub-itineraris són visitats peró seguint un ordre [i1,i2...in]), de alternatives (només és visitarà un dels sub-itineraris, depen d'una certa condició <i1,i2...in>) o de conjunts (també es visiten tots els sub-itineraris peró a diferencia de les seqüències en aquest cas no segueixen cap ordre {i1,i2...in}). Un exemple de itinerari explicit, és el que es va comentar a classe, del que es pot fer en una tarda-nit, sortint amb la teva parella. L'agent comprarà una entrada pel teatre i reservarà taula en un restaurant o bé comprarà un parell d'entrades per al museu i li quedaran dines per poder pagar una taula en un restaurant més car. Com que vas amb la parella, abans o després de les opcions comprarà un ram de flors. Aquest itinerari el podriem explressar d'aquesta manera:
També
forma part de l'arquitectura de l'agent mòbil certs mecanismes de
control (migració) i certs mecanismes de protecció com són l'ús de
dades xifrades i algorismes de desxifrat i descodificació.
Aquestes
arquitectures possibiliten els agents autocontinguts i la incormporació
de nous mecanismes de protecció sense haber d'aturar ni recompilar les
agències.
Uns mecanismes de protecció, com bé hem dit abans, són els criptogràfics
que assegura l'estructura de l'agent no es pugui alterar-se ni
llegir-se fora d'una agència concreta. Gracies també als mecanismes de
protecció de l'estructura especial que les arquitectures d'agents
mòbils tenen per emmagatzemar resultats, fan que sigui privat els
resultats obtingut per l'agent.
Results = Eo(nil, Id1), So(H(Eo(nil, Id1))),
Eo(R1, Id2), S1(H(Eo(R1, Id2))), ...
Eo(Rn, Ido), Sn(H(Eo(Rn, Ido)))
E: Xifrat, H: Hash, S: Signatura, Id: Identitat de l’agència
El JADE/MARISM-A està capacitat per utilitzar diverses arquitectures d'agents mòbils de manera simultania, es a dir, pot usar diverses arquitectures a la vegada, algunes de les quals les té predefinides. Són les següents:
Agent Estàtic
Agent Mòbil amb itinerari implicit
Agent Mòbil amb itinerari explícit imbricat (ceba)
Agent Mòbil amb itinerari explícit no imbricat (scrambled)