Relazione - Università di Bologna

Transcript

Relazione - Università di Bologna
PERMESSO (PERsistent MESSaging in ad hOc networks)
Ermete Gaudenzi – matr. 0000231758
Corso di laurea specialistica in Ingegneria Informatica
Università di Bologna
Reti di Calcolatori LS – Prof. Antonio Corradi – A.A. 2005-06
Referente progetto: Eugenio Magistretti
Gabicce Mare, 30-01-2007
Abstract
I
servizi
di
messaggistica
istantanea
rappresentano oggi un rilevante campo
applicativo, soprattutto grazie alla notevole
espansione che si ha avuto nel loro utilizzo (basti
pensare agli innumerevoli client quali MSN, ICQ,
AIM, che nel giro di pochi anni hanno preso
prepotentemente piede).
Il fine ultimo di tali applicazioni può essere
molteplice: da un lato infatti l’obiettivo è
essenzialmente quello di comunicare con altri
utenti della rete che utilizzano lo stesso client;
utenti che possono essere amici, conoscenti,
colleghi di lavoro; non solo quindi situazioni di
svago, ma anche possibilità concreta da parte di
un’azienda di far comunicare tra loro dipendenti
di uffici diversi.
Tali servizi, così come sono pensati, necessitano
per forza di cose di un’infrastruttura per la
gestione delle comunicazioni, e quindi la
presenza di un componente aggiuntivo (quale ad
esempio un server). Allo stesso tempo è
necessario un collegamento a internet per poterne
usufruire.
Quello che si vuole realizzare con PERMESSO è
un sistema in grado di garantire messaggistica
istantanea tra utenti appartenenti ad una stessa
MANET wireless (Mobile Ad-hoc NETwork)
senza bisogno di un’infrastruttura di servizio (che
come tale ovviamente rappresenterebbe un costo
aggiuntivo).
Introduzione
Quello che vogliamo realizzare con questo
progetto è un servizio di messaggistica istantanea
(d’ora in avanti, chat) utilizzabile in Mobile Ad
hoc NETworks (MANET), reti wireless che
possono essere utilizzate da dispositivi come
laptop, PDA e smart phone, o più in generale da
dispositivi che presentino almeno un’interfaccia
802.11.
Per come viene concepito il servizio quindi non è
richiesta connessione internet né alcun tipo di
supporto infrastrutturale (come ad esempio degli
access point), semplicemente la rete viene
generata automaticamente quando almeno due
dispositivi entrano nel raggio di funzionamento
delle rispettive schede wireless. È ovvio quindi
che tali reti, proprio per loro stessa natura, sono
molto dinamiche e altamente variabili nel tempo.
Il tutto viene quindi gestito direttamente dai
singoli terminali (o, si veda successivamente nel
paper, al più da un server) che possono così
autonomamente entrare nella rete, scambiarsi
messaggi e uscire. In particolare, per quanto
riguarda lo scambio di messaggi, ci vengono
richieste due tipologie comunicative (per i
dettagli si rimanda alle sezioni successive):
•
chatting sincrono, nel quale i due host
interessati allo scambio di messaggi sono
contemporaneamente presenti all’interno
della stessa MANET;
•
chatting asincrono; in questo caso uno dei
due host è momentaneamente offline e per
questo motivo bisognerà realizzare un
meccanismo in grado di inoltrare il
messaggio non appena il destinatario
diventerà
nuovamente
raggiungibile
all’interno della MANET.
Ovviamente, così come avviene nei “classici”
programmi di chat, è possibile inviare un
messaggio a qualcuno solamente se è presente
nella nostra “lista amici”: per amicizia si intende
un legame biunivoco che lega due specifici host,
legame che si instaura a fronte di una richiesta (e
conseguente conferma) e che può essere interrotto
in qualsiasi momento.
Il recapito dei messaggi nel caso di chatting
asincrono può avvenire in modo autonomo da
parte degli host oppure mediante un'infrastruttura
di servizio, denominata persistent server. Nel
primo caso i messaggi da recapitare si spostano
da host in host cercando di rimanere su chi è
online nella rete. Nel secondo caso invece
vengono mandati direttamente al server che si
prende la responsabilità di inoltrarli.
Si è scelto di non adottare alcuna misura riguardo
alla raggiungibilità di rete per i motivi sopra
evidenziati (mancanza di standard e non
portabilità). Pertanto si suppone che tutti gli host
appartenenti alla MANET siano raggiungibili fra
loro. Come estensione futura si potrebbe
aggiungere un protocollo di routing come livello
di rete intermedio, situato al si sotto di quello di
PERMESSO senza modificarne il funzionamento.
In seguito sono approfonditi alcuni aspetti sulla
rete PERMESSO di carattere generale, per poi
scendere nel dettaglio delle scelte di progetto e
terminare con alcune informazioni di base
sull'implementazione.
Identificazione degli host
Considerazioni generali
Raggiungibilità di rete
Una delle caratteristiche delle MANET è la non
completa raggiungibilità fra gli host. E' possibile
per esempio che tre host A B C siano disposti
spazialmente in modo tale che B vede gli altri due
e gli altri due vedono solo B. Inoltre si possono
muovere
cambiando
la
condizione
di
raggiungibilità nel tempo. Questo problema è
complesso da gestire in quanto occorre introdurre
un protocollo che permette di monitorare la rete
nel tempo e calcolare i percorsi migliori per
l'instradamento dei dati. Purtroppo non esistono
ancora standard definitivi sull'argomento e
l'organizzazione IETF si sta prendendo cura di
definirli.
In attesa dello standard definitivo sono stati
proposti molti protocolli che si possono
suddividere in due gruppi principali: reactive e
proactive. I reactive si propongono di trovare un
percorso valido solo quando necessario, cioè
quando ci sono pacchetti da trasmettere. Il
vantaggio consiste nel basso uso della rete in caso
di inattività mentre gli svantaggi sono il ritardo
introdotto dal discovery e il traffico generato di
conseguenza. I protocolli proactive invece
mantengono sempre le informazioni per
l'instradamento al costo di un continuo uso della
rete per il discovery e la distribuzione delle
tabelle di instradamento. Attualmente esistono
implementazioni in C/C++ di alcuni protocolli
con anche un'interfaccia Java, tuttavia non sono
facilmente portabili su cellulari e palmari in
quanto si basano su librerie native.
Gli host devono essere in grado di riconoscersi
fra loro. Una prima soluzione potrebbe essere di
riconoscerli in base all'indirizzo IP, ma è
scomoda perchè introduce un vincolo forte a
livello di rete. Avendo migliaia di utenti
occorrono migliaia di IP, a prescindere dal
numero di client connessi in un dato istante. Una
soluzione più promettente è quella di assegnare
ad ogni host un identificativo univoco e usare
quello per riconoscerlo. In questo modo
l'indirizzo di rete del dispositivo diventa
irrilevante.
Rimane il problema dell'assegnazione degli
identificativi: per ogni nuovo client si deve
garantirne l'univocità. A tale scopo si potrebbe
introdurre una fase di elezione dove sono gli altri
ad assegnare l'ID oppure fare in modo che
ognuno si generi il proprio in modo il più
possibile casuale per diminuire le collisioni. Nel
primo caso non è detto che l'elezione dia risultati
positivi in quanto la scelta dipende da tutti gli
altri host esistenti, anche quelli attualmente
offline. In entrambi i casi quindi è una scelta
probabilistica.
Generare un identificativo localmente assumendo
che sia univoco è molto più semplice e meno
costoso rispetto ad un protocollo di elezione; in
altre parole è più conveniente. Occorre fare in
modo che sia il più possibile casuale e stabilirne
una lunghezza adeguata.
A tal scopo esiste lo standard UUID (Universally
Unique Identifiers) che fornisce le specifiche per
generare un numero di 128bit unico. L'ideale
sarebbe generarlo tenendo conto dell'indirizzo
MAC, cosa che però non è possibile su
piattaforma J2ME perchè tale informazione è
inaccessibile. Una possibile scelta ricade dunque
su UUID random-based.
Probabilità di collisione dell'ID
La probabilità di collisione di due ID generati
casualmente è calcolabile con la teoria del
paradosso dei compleanni. Tale teoria evidenzia
che anche in un gruppo piccolo di 23 persone la
probabilità che due di loro festeggino il
compleanno lo stesso giorno è molto alta, circa il
50%. Nel nostro caso abbiamo un insieme di n
host, uno spazio di x possibili ID e la probabilità
di collisione p. La formula esatta di p(n,x) è
troppo complessa da calcolare per grandi numeri
di x o di n.
p n , x=1− p n , x
1
2
n−1

p n , x =1⋅1− ⋅1− ⋅⋅1−
x
x
x
x⋅ x−1⋅⋅ x −n1
x!
= n
p n , x =
n
x
x ⋅ x−n!
Esiste tuttavia una formula approssimata più
adatta alla computazione.
2
p n≈1−e
−n
2⋅x
Il seguente grafico mostra la probabilità di
collisione in funzione del numero di bit dell'ID e
del numero di host presi in esame. Il numero di
possibili ID è x=2bits . Per mortivi di chiarezza
grafica log10(p) viene mostrato ugualmente
anche per p=0.
futuri; questo influenza notevolmente i conti.
Supponiamo un numero di host pari a 1.000.000,
per mantenere la probabilità intorno a 1E-10
basterebbero 72bit. Un UUID random-based ha
122 bit casuali su 128, 50bit (~6 byte) al di sopra
del caso precedente, con una probabilità di
collisione inferiore a 1E-15. Considerando che gli
UUID sono standard e l'overhead introdotto è
minimo si è optato per questa soluzione.
Autenticazione
In assenza di un sistema centralizzato di
accounting per autenticare correttamente gli
utenti emergono notevoli problemi. Nel modello
client/server è il server a gestire un sistema di
riconoscimento per esempio con nome utente e
password. Ad ogni connessione il client deve
autenticarsi ed ogni messaggio dal/al singolo
client passa tramite il server che in un certo senso
lo certifica. Nel modello peer-to-peer questo non
è possibile perchè non vi è alcun servizio che
certifica l'identità dei vari host. Per esempio se
ogni host firmasse i propri messaggi con un
codice univoco gli altri host lo conoscerebbero e
potrebbero facilmente copiarlo per emettere
messaggi a nome suo. Si potrebbe introdurre un
sistema di firme digitali con crittografia
asimmetrica per risolvere questo problema: ogni
host memorizza la chiave pubblica degli altri host
e controlla la loro identità mediante uno scambio
di tipo challenge-response. Tuttavia occorre tener
presente che la computazione è molto onerosa per
un dispositivo portatile a batteria e che la
piattaforma J2ME non integra tali funzionalità.
L'unico modo per realizzarle sarebbe di basarsi su
una libreria esterna nativa con relativa interfaccia
Java, rinunciando però alla completa portabilità.
Per questi motivi si è scelto di non introdurre
particolari
misure
di
sicurezza
per
l'autenticazione degli host.
Riservatezza dei dati
Illustration 1: Probabilità di collisione ID degli host
In un caso reale gli host appartenenti alla stessa
MANET difficilmente supererebbero quota
1.000. Tuttavia un host può muoversi da una rete
all'altra nel tempo e quindi occorre considerare
tutti gli host di tutte le reti: passati, presenti e
Per quanto riguarda la riservatezza dei messaggi
scambiati, un utente malintenzionato potrebbe
modificare l'applicazione, o scriverne una ad-hoc,
per esempio per mostrare all'utente il contenuto
dei messaggi altrui memorizzati sul proprio
dispositivo, oppure per modificarli. L'unico modo
per evitare ciò è introdurre anche qui funzionalità
di crittografia che, per i medesimi motivi
evidenziati sopra, non abbiamo realizzato.
nella ricerca per alias; contiene la stringa
da cercare e il tipo di ricerca (match esatto
o parziale)
Progetto
Comunicazione fra host
Le specifiche richiedono esplicitamente uno
scambio di messaggi basato sul protocollo UDP.
La piattaforma J2ME con MIDP 2.0 mette a
disposizione tali funzionalità attraverso le classi
Datagram e UDPDatagramConnection. Occorre
definire un protocollo di comunicazione per il
formato dei datagrammi e la semantica di
comunicazione. Considerando che ci sono diversi
tipi di messaggi, che questi possono essere
inoltrati tramite terzi e che si vuole introdurre il
concetto di ordinamento causale, si è giunti alla
definizione della struttura di un messaggio,
denominato pacchetto, con la seguente struttura:
•
service: tipo di servizio
•
senderID: ID del'host mittente
•
receiverID: ID dell'host destinatario
•
timestamp: informazione necessaria per
gestire l'ordinamento
I pacchetti si possono suddividere in due gruppi
principali: quelli che necessitano di cure
particolari per il recapito offline e quelli che
possiamo permetterci di perdere. E' chiaro che è
importante che tutti i pacchetti arrivino a
destinazione ma per alcuni di essi è più
importante che per altri.
•
QUERY_ALIAS_RESPONSE: risposta
alla ricerca per alias; contiene l'alias
completo del client che risponde
•
FRIENDSHIP_ASK:
richiesta
amicizia; necessita di recapito offline
•
FRIENDSHIP_YES: conferma positiva di
amicizia; necessita di recapito offline
•
FRIENDSHIP_NO: conferma negativa di
amicizia; necessita di recapito offline
•
FRIENDSHIP_END: notifica di fine
amicizia; necessita di recapito offline
•
FREE_MEMORY_ASK:
inviato
in
broadcast in assenza del persistent server
per richiedere la quantità di memoria
libera degli altri host
•
FREE_MEMORY_RESPONSE: risposta
alla richiesta di memoria libera; contiene
questa informazione
•
FORWARD: contiene altri pacchetti che
necessitano di recapito offline; usato per
inoltrarli tramite terzi; necessita di
recapitato offline
di
Segue una descrizione dei tipi di pacchetti usati.
Alcuni di essi si riferiscono a funzionalità
analizzate in seguito o nelle relazioni degli altri
componenti del gruppo. Per ciascuno di essi è
anche indicato se necessita di cure per il recapito.
•
JOIN_NETWORK: inviato in broadcast al
momento di ingresso nella rete
•
LEAVE_NETWORK:
inviato
in
broadcast al momento di uscita dalla rete
•
HOST_ONLINE: notifica a un host
appena entrato che siamo presenti online
•
TEXT_MESSAGE: messaggio di testo fra
due client; contiene il testo e la data/ora di
invio (utile per i test); necessita di recapito
offline
•
DUMMY: comunica la porta di rete di
invio del mittente; usato durante l'apertura
di una conversazione
•
QUERY_ALIAS: inviato in broadcast
Illustration 2: Diagramma degli stati di un pacchetto
Dato che ogni host è identificato dal suo ID
anzichè dal suo indirizzo di rete, si suppone che
al momento di invio di un pacchetto il campo
senderID contenga l'ID dell'host che lo manda
fisicamente. Questa considerazione potrebbe
sembrare banale ma è di fondamentale
importanza per la gestione del recapito dei
messaggi offline, gestiti unicamente mediante i
FORWARD.
A livello locale ogni client associa uno stato ad
ogni pacchetto per ricordarsi come lo deve
trattare. I possibili stati sono sei:
•
CREATED: appena creato
•
SEND_WAIT: tutti i dati del pacchetto
sono stati preparati ed è pronto per l'invio
•
SEND_COMPLETE: è stato inviato nella
rete il datagramma UDP corrispondente
•
PROCESS_WAIT: appena ricevuto, in
attesa di essere processato
•
PROCESS_COMPLETE:
correttamente
•
DROPPED: c'è stato qualche errore, per
esempio il pacchetto era inatteso
si può risalire al suo host ID
•
Alias locale, modificabile
•
Stato: uno dei 5 possibili stati
La relazione di amicizia è di tipo biunivoco,
ovvero o entrambi sono amici oppure non si
conoscono. Fra due client A e B nel momento in
cui A decide di terminare l'amicizia rimuovendo
B dalla sua rubrica, glielo comunica all'altro che
completa l'operazione rimuovendo A dalla sua.
processato
Rete dal punto di vista del client
Ogni host ha la propria visione della rete a cui sta
partecipando, ha la sua rappresentazione degli
altri host e delle informazioni ad essi associate:
•
ID di rete PERMESSO
•
stato (online, offline)
•
indirizzo IP di rete, se online
•
porta UDP per la conversazione, se instaurata
Un host viene posto in stato online alla ricezione
di un qualsiasi pacchetto proveniente da lui e
viene posto offline alla ricezione di un
LEAVE_NETWORK.
Ogni client conosce sempre tre host speciali:
quello locale, il broadcast e il persistent server.
L'host locale è trattato in modo identico agli altri
con la differenza che è sempre online. Anche il
broadcast è sempre online ed ha ID fisso e
indirizzo di rete non modificabile. Il persistent
server ha anch'esso ID fisso come il broadcast.
Relazione di amicizia
Dal punto di vista di un client un amico è
caratterizzato dalle seguenti informazioni:
•
Host al quale è associato, tramite il quale
Illustration 3: Diagramma degli stati di un amico
Quando due client vogliono instaurare una
relazione di amicizia devono conoscersi: il client
A effettua una ricerca per alias e sceglie B in base
alle risposte che gli giungono dagli host
attualmente online. A questo punto A invia una
richiesta di amicizia a B, che la mostra all'utente
in attesa di conferma. Quando l'utente di B ha
deciso cosa fare, B manda ad A una conferma
positiva o negativa e l'amicizia si instaura di
conseguenza. Se la conferma è positiva B
aggiunge immediatamente A come amico ed A
aggiunge B quando la riceve. Se invece è
negativa si torna allo stato iniziale prima della
ricerca. Ovviamente ogni client deve ricordarsi
tutte le richieste di amicizia inviate e ricevute.
Nell'implementazione attuale al momento di invio
o ricezione di una richiesta di amicizia viene
aggiunto un amico temporaneo in rubrica in uno
dei due stati di non-confermato, ovvero richiestainviata e richiesta-ricevuta. Alla ricezione o invio
della conferma di amicizia questo amico viene
eliminato se la conferma è negativa, oppure il suo
stato viene aggiornato opportunamente.
Messaggi e conversazioni
I messaggi di testo mostrati all'utente sono
indipendenti dai pacchetti che li trasportano nella
rete, pertanto sono da gestire separatamente. Un
messaggio di testo è così formato:
disconnette dalla rete.
Nella nostra implementazione attuale la
conversazione sincrona di rete è gestita in
accordo con le specifiche (un thread dedicato per
ogni conversazione) ma l'interfaccia grafica
presenta tutti i messaggi insieme, in modo
analogo a come un telefono cellulare mostra gli
SMS ricevuti.
All'inizio di una conversazione sincrona l'host A
che vuole inviare il primo messaggio crea
internamente un gestore associato ad una porta
UDP casuale e manda il messaggio tramite esso
verso la porta di default del destinatario B. A quel
punto B si accorge che ha ricevuto un messaggio
da A ad una porta diversa da quella di default e
crea a sua volta un gestore interno sempre
associato ad una porta casuale. Infine esso
provvede a notificare immediatamente ad A la
sua porta locale inviando un pacchetto di tipo
DUMMY da essa. La conversazione è ora
instaurata e tutti i messaggi futuri verranno inviati
nelle nuove porte che i due host si sono
scambiati. Al momento di uscita dalla rete di uno
dei due la conversazione viene automaticamente
chiusa da entrambi.
•
sender: amico mittente
•
receiver: amico destinatario
•
localTime: data/ora di ricezione locale
•
sendTime: data/ora di invio; notare che gli
orologi dei client non sono sincronizzati
•
text: corpo del messaggio
Recapito dei pacchetti offline
•
unread: messaggio ricevuto ma non
ancora letto
•
unsent: messaggio in coda di invio ma
non ancora inviato
Dato che i messaggi di testo sono pacchetti e che
ci sono altri tipi di pacchetti che necessitano di
recapito offline, si è scelto di gestirlo a livello di
pacchetto.
Occorre notare che uno dei due campi fra sender
e receiver è il client locale, che viene gestito
come se fosse un amico non appartenente alla
rubrica. I campi sendTime, localTime, unread e
unsent sono facoltativi e sono stati introdotti per
completezza, per dare qualche informazione in
più all'utente.
Per limitare l'utilizzo di memoria è stato imposto
un limite al numero di messaggi memorizzabili
sia in ingresso che in uscita, superato il quale
viene eliminato il messaggio più vecchio per
lasciar spazio a quello nuovo.
Due amici possono scambiarsi messaggi di testo
in modo sincrono o asincrono. Nel primo caso A
manda un messaggio a B che è però offline e il
delivery viene gestito di conseguenza. Nel
secondo caso invece sono entrambi online e si
instaura una conversazione diretta. Essa termina
automaticamente quando uno dei due client si
Se l'host destinatario è offline ci sono due
possibili scenari, con e senza persistent server. Se
c'è il persistent server il pacchetto viene inoltrato
a lui tramite un FORWARD e il client poi se ne
dimentica. Nel caso che nemmeno il server sia
presente il client si tiene il messaggio in locale in
attesa che il destinatario arrivi online oppure che
l'utente decida di lasciare la rete. In quest'ultimo
caso viene effettuato un discovery sulla memoria
libera degli altri host attraverso i pacchetti
FREE_MEMORY_ASK e FREE_MEMORY_RESPONSE e vengono inviati i pacchetti in
sospeso, in stato SEND_WAIT, all'host con più
spazio libero disponibile. Il client sa quanta
memoria libera ha l'host destinatario e si regola in
modo tale da non eccedere questa quota. I
pacchetti rimanenti vengono inviati al secondo
candidato in ordine di spazio libero e così via.
Dall'altro lato il client ricevente apre il
FORWARD e aggiunge i pacchetti al suo interno
nella propria memoria in stato SEND_WAIT. In
caso non ci sia abbastanza memoria per salvarli
vengono automaticamente scartati quelli più
vecchi, facendo riferimento al timestamp.
Suddivisione in package
•
permesso: interfacce della libreria
accedere alle funzionalità offerte
•
Il persistent server
Il persistent server ha come unico scopo quello di
raccogliere i pacchetti da inoltrare che gli
vengono mandati e restare in attesa che i
destinatari vengano online. A tal fine deve
mantenere nella sua memoria interna un gran
numero di pacchetti.
Generalmente si suppone che il persistent server
sia sempre presente all'interno della rete, tuttavia
nel caso che venga attivato in presenza di altri
host, quando questi si accorgono della sua
presenza dal suo pacchetto di JOIN gli mandano
tutti i loro pacchetti in attesa di inoltro, delegando
a lui la responsabilità di recapito. Questa
operazione potrebbe causare la congestione della
rete e per evitarlo è stato introdotto un ritardo
casuale fra il momento in cui il client si accorge
della presenza del server e l'invio del pacchetto di
FORWARD.
•
•
per
lcdui: interfaccia grafica di esempio
•
contact: gestione della rubrica
•
message: gestione dei messaggi
•
server: GUI del server
util: utilità varie come logging, quick-sort,
generazione UUID, gestione dei task
stud.retils.permesso: implementazione delle
interfacce definite nel package permesso
•
io: serializzazione dei dati su data stream
•
net: tutto ciò che riguarda la gestione della
comunicazione di rete
•
host: gestione della visione della rete
dal punto di vista locale
•
packet: gestione dei pacchetti
Architettura logica
Il diagramma mostra l'architettura riassunta dei
componenti realizzati nel prototipo.
Implementazione
Organizzazione generale
Come organizzazione generale del codice si è
scelto di utilizzare il pattern MVC con le classi
J2ME come View, una libreria di interfacce Java
come Model e gestione dell'interfaccia grafica
come Controller. In altre parole l'interfaccia
grafica da noi realizzata è il cliente di una libreria
che gestisce le funzionalità del client
PERMESSO, presentandole come insieme di
interfacce Java. Gli obiettivi raggiunti con questa
architettura sono molteplici: dalla corretta
divisione delle responsabilità alla facile
suddivisione del lavoro. Inoltre abbiamo ottenuto
anche la separazione fra definizione delle
funzionalità offerte e loro implementazione e
l'offuscamento di tutte le funzionalità di gestione
interna, aumentando la chiarezza ed eliminando
problemi derivati dal loro abuso da parte dei
clienti della libreria: l'interfaccia grafica.
Illustration 4: Diagramma architetturale dei componenti
L'area verticale evidenziata in giallo mostra lo
stack per la comunicazione di rete. L'area
orizzontale evidenziata in rosso rappresenta il
livello di astrazione dei pacchetti dai datagrammi.
I componenti in azzurro sono quelli principali
usati dai clienti della libreria per accedere alle sue
funzionalità.
(de)serializzazione
dei
pacchetti
PERMESSO da/a stream binari
•
PacketFactory: gestisce la creazione dei
pacchetti
•
PacketStore: permette di memorizzare i
pacchetti nella memoria permanente del
dispositivo
•
Help: comprende il supporto alla
serializzazione generica di classi, il
logging, la gestione della configurazione
permanente e altre utilità di tipo verticale
Segue la descrizione delle responsabilità dei
singoli componenti.
•
GUI: presenta all'utente le funzionalità
della libreria PERMESSO
•
ClientMidlet: midlet di avvio del client,
inizializza Client e la GUI
•
ServerMidlet: midlet di avvio del server,
inizializza Server e la GUI del server
•
Client: componente di accesso alle
funzionalità del client. Gestisce la ricerca
degli host per alias e l'integrazione fra
ContactList e MessageManager
•
Server: componente di accesso alle
funzionalità del server. Permette l'acesso
ad alcune informazioni come i messaggi
da inoltrare e gli host di rete conosciuti
•
ContactList: gestisce la rubrica di un
client
•
Friend: rappresenta un amico in rubrica
•
MessageManager: gestisce i messaggi di
testo di un client in ingresso e in uscita
•
TextMessage: rappresenta un messaggio
di testo
•
Host: rappresenta un host della rete
•
Connection: gestisce la logica del
protocollo
PERMESSO.
Fa
da
intermediario fra Client o Server e il
Router.
•
PacketRouter: gestisce l'invio/ricezione
dei pacchetti in modo centralizzato,
gestisce le conversazioni
•
PacketDispatcher:
wrapper
di
PacketConnectionUdp che integra un
thread di ricezione
•
•
PacketConnectionUdp: astrae dalle classi
J2ME una socket UDP con I/O orientato a
pacchetti PERMESSO
PacketSerializer:
si
occupa
della
I componenti qui evidenziati non corrispondono
direttamente alle classi Java realizzate. In
particolare Connection e PacketRouter sono in
realtà sdoppiati in due versioni, una per il client e
una per il server. PacketConnectionUdp è
realizzata in modo tale da consentire
l'introduzione di connessioni TCP come sviluppo
futuro.
Per
ogni
altro
chiarimento
sull'implementazione attuale si veda direttamente
il codice, ampiamente commentato.
Permanenza dei dati
La permanenza dei dati nella memoria del
dispositivo è gestita tramite le funzionalità offerte
dal J2ME, ovvero i record store e la PIM. Fra i
vari depositi di dati permanenti troviamo la
configurazione, l'elenco dei messaggi, l'elenco dei
pacchetti e l'elenco degli amici. La
memorizzazione avviene tramite le utility di
serializzazione dati (package stud.retils.permesso.io). Gli amici possono anche essere
salvati tramite le API della PIM, se disponibili,
creando nuovi contatti e salvando le informazioni
necessarie nel campo NOTE.
Conclusione
Il progetto realizzato copre tutti i casi richiesti
nelle specifiche e realizza in più l'identificazione
degli host tramite ID e l'ingresso e uscita del
persistent server nella MANET.
I punti di forza di questo progetto sono:
•
dinamicità degli indirizzi IP degli host;
essendo riconosciuti in base al loro ID
•
astrazione a pacchetti introdotta; la
comunicazione è indipendente dal
trasporto di rete usato
•
architettura modulare; aumenta gli scenari
d'uso, semplifica le future estensioni,
predispone al test automatizzato dei
componenti
I punti di forza del prototipo sono:
•
realizzazione quasi completa delle
funzionalità; per realizzare l'applicazione
finale si può partire dal prototipo ed
estenderlo
•
corretta suddivisione delle responsabilità
fra le classi
•
codice di servizio verticale scritto in modo
il più possibile indipendente dal resto per
favorire la riusabilità
•
tutti i parametri operativi significativi
sono configurabili; alcuni a tempo di
compilazione, come timeout e numero
massimo di pacchetti inoltrabili mediante
un FORWARD; altri sono modificabili a
runtime come il numero massimo di
messaggi di testo e la porta di rete
Dall'altro lato della medaglia l'architettura
modulare ha portato ad un aumento di
complessità:
il
prototipo
realizzato
è
computazionalmente più pesante da eseguire in
confronto a soluzioni più essenziali e ugualmente
funzionanti.
Sviluppi futuri
Per quanto riguarda la parte grafica si potrebbe
migliorare notevolmente quella esistente ed
implementare la gestione delle conversazioni. Da
notare che la GUI è solo uno dei possibili clienti
della libreria, è possibile come estensione futura
scrivere dei BOT, proporre interfaccie grafiche
alternative o integrare la libreria in un progetto
più ampio.
Per la parte di rete sarebbe opportuno aumentare
la separazione fra PacketRouter e Connection
spostando la gestione di tutti i pacchetti dentro
quest'ultima. Inoltre si potrebbe sollevare
PacketRouter dalla gestione dei dispatcher e
incaricare di ciò la connessione o addirittura il
Client. Infine resta da implementare la
trasmissione con ACK per evitare la perdita di
pacchetti dovuta alla rete, in quanto con il codice
attuale l'applicazione risente pesantemente della
qualità della rete sottostante.
La duplicazione dei pacchetti da inoltrare e
l'eliminazione dei duplicati ricevuti non è
implementata e sarebbe una funzionalità chiave
da aggiungere per risolvere il problema della
caduta di un nodo.
Bibliografia
•
Documento delle specifiche di progetto
•
Documentazione di J2ME, MIDP e CLDC
•
http://en.wikipedia.org/wiki/Birthday_paradox:
analisi delle collisioni fra host ID
•
http://www.opengroup.org/onlinepubs/962939
9/apdxa.htm: per le specifiche sugli UUID
•
http://www.ietf.org/html.charters/manetcharter.html: protocolli di routing su MANET