Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo...

35
REALIZZAZIONE DI APPLICAZIONI DI STREAMING P2P Federico Bertolini 1

Transcript of Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo...

Page 1: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

REALIZZAZIONE DI APPLICAZIONI DI STREAMING P2P

Federico Bertolini

1

Page 2: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

Sommario

Cap. 1 – Il Peer-to-Peer (P2P)1.1 – L'architettura dei Sistemi P2P1.2 - I Sistemi simil-P2P1.3 - I Vantaggi e gli Svantaggi del P2P1.4 - L'Impatto Socio-Economico del P2P1.5 - Il Futuro del P2P

Cap. 2 – Lo Streaming in Internet 2.1 – La TV nel Web. 2.2 – La P2P TV come evoluzione della WebTV

Cap. 3 – Come creare un'applicazione per lo Streaming P2P3.1 - La libreria GRAPES3.2 – La topologia della rete: la Struttura ad Albero

Cap. 4 – Applicazione per lo Streaming P2P4.1 – Analisi del codice4.2 - Implementazioni future

BibliografiaLink UtiliCodice Completo

2

Page 3: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

1 - Il Peer-to-Peer (P2P)

Oggigiorno qualsiasi utente di internet sa più o meno consciamente cosa sia una rete Peer-to-Peer (abbreviata in P2P), basti pensare alla rete Bittorrent o alla rete eDonkey, due perfetti esempi di reti P2P utilizzate per il File Sharing (ovvero la condivisione di files). In generale una rete P2P è una rete nel quale ogni computer può interagire con gli altri computer della rete sia come client che come server, quindi sia usufruire che fornire un servizio di qualunque natura esso sia, senza il bisogno di un computer server centrale che faccia da intermediario. Quindi nel P2P i vari computer (o per meglio dire: “nodi”) non hanno alcun tipo di gerarchia, ma sono tutti nodi paritari (“peer” infatti in inglese significa “pari”).

Illustrazione 2: Un sistema centralizzato basato su Server

Come detto prima mediante questa configurazione qualsiasi nodo è in grado di avviare o completare una transazione. I nodi benché equivalenti sul piano del trattamento possono differire nella configurazione locale, nella velocità di elaborazione, nella ampiezza di banda e nella quantità di dati memorizzati.

Benché già concepito agli inizi degli anni '90 e utilizzato in ambito delle reti locali il P2P salì alla ribalta nel 1999 quando fu rilasciato il sistema di condivisione dei file di Napster. Fu una grande conquista, per la prima volta tutti i computer di una rete erano messi in condizione egualitaria.Il concetto ispirò nuove strutture e filosofie, arrivò persino a superare l'ambito tecnologico, e ad entrare nell'ambito sociologico descrivendo processi sociali che avevano una dinamica “Peer-to-Peer” appunto.

1.1 – L'Architettura dei Sistemi P2P

Di norma un sistema P2P implementa una rete overlay astratta, costruendo un livello applicativo che si occupa dell'indicizzazione o della scoperta dei peer, rendendo dunque il sistema indipendente dalla topologia fisica della rete. In questi versi bisogna segnalare che i sistemi di P2P anonimo

3

Illustrazione 1: Un sistema di nodi peer-to-peer

Page 4: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

implementano ulteriori livelli di routing per oscurare l'identità della fonte e della destinazione.

Come già detto in precedenza in una rete P2P non esistono i concetti di client o server separati, ma solo di peer, ovvero di questi nodi che contemporaneamente funzionano sia come client che come server.La rete P2P overlay consiste quindi in tutti questi peer che partecipano alla rete in qualità di nodi.Si instaurano pertanto dei collegamenti tra questi nodi, e in base a come siano collegati questi nodi possiamo classificare le reti P2P in due categorie: reti strutturate e non strutturate.

Nelle reti P2P strutturate i peer sono organizzati seguendo specifici algoritmi e criteri. Di norma i peer usano Tabelle Hash Distribuite (Distribuited Hash Table, DHT).Reti P2P strutturate sono ideali per implementazioni su larga scala data l'alta scalabilità e le garanzie sulle performance ( generalmente approssimate in O(log N), dove N è il numero di nodi della rete.)

Una rete P2P non strutturata invece non impone alcuna struttura alla rete. I peer di connettono l'un l'altro secondo poche e semplici regole. Idealmente tali reti non dovrebbero avere elementi o nodi centralizzati, ma in pratica possiamo differenziare i sistemi non strutturati proprio in base al grado di centralizzazione. Possiamo distinguere 3 categorie:

• Nei sistemi P2P puri (o decentralizzati) l'intera rete è costituita da peer equipotenti, c'è solo un livello di routing e non ci sono dei nodi preferenziali con un qualche tipo di funzione.

• Nei sistemi P2P centralizzato c'è un server centrale con funzioni di indicizzazione e per dare ai nodi una visione dell'intero sistema. Si differenzia con le reti strutturate solamente perché i nodi non si connettono tra loro con un qualche algoritmo particolare.

• Infine i sistemi P2P ibridi permettono l'esistenza di nodi “infrastrutturali”, chiamati di solito Supernodi.

Se volessimo fare degli esempi, Napster, il primo popolare sistema P2P, era un sistema P2P centralizzato, attualmente la rete eDonkey è un sistema centralizzato. Freenet e le prime implementazioni di Gnutella sono dei sistemi decentralizzati, mentre l'attuale implementazione di Gnutella (Gnutella2) è un sistema ibrido.

1.2 – I Sistemi simil-P2P

Quanto fin'ora descritto rientra nelle attuali definizioni di peer-to-peer, tuttavia il concetto che sta alla base del P2P era già stato discusso per sistemi software e reti precedenti, possiamo risalire già ai principi enunciati nella prima RFC.

Un sistema di scambio di messaggi che è molto spesso citato come precursore dell'architettura P2P è il sistema di scambio delle news tra server Usenet. E' ancora un sistema client-server nella fase di prelievo o invio delle notizie da parte del client/utente, ma i vari server comunicano tra loro come fossero peers per la diffusione delle news tra tutti i server della rete. Stesso discorso vale per il protocollo SMTP, nel senso che tra loro i server scambiano messaggi come fossero peers, mentre vi è ancora un rapporto client-server con i vari client mail appunto. Il World Wide Web stesso, nella visione di Tim Berners-Lee, era molto simile ad una rete P2P, nel senso che ogni utenti del web sarebbe dovuto essere un “utente attivo”, un contributore nella creazione e linking dei contenuti per

4

Page 5: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

creare dunque una rete di link. Questo contrasta a pieno con la struttura del Web che si è sviluppata nel corso degli anni.

1.3 – I Vantaggi e gli Svantaggi del P2P

Vantaggi e svantaggi sono relativi al tipo di ambiente in cui si decide di installare questo tipo di rete, ma sicuramente si deve tenere presente che:

• Non si deve acquistare un server con potenzialità elevate e quindi non se ne deve sostenere il costo, ma ogni computer deve avere i requisiti per sostenere l'utente in locale e in rete, ma anche gli altri utenti che desiderano accedere alle risorse di questo in remoto;

• Ogni utente condivide localmente le proprie risorse ed è amministratore del proprio nodo. Questo da un lato può essere positivo per una questione di "indipendenza", ma dall'altro richiede delle competenze ad ogni utente, soprattutto per quel che concerne la protezione;

• La velocità media di trasmissione dei dati è molto più elevata di una classica rete con sistema Server / Client, dal momento che l'informazione richiesta da un Client può essere reperita da numerosi Client, anziché da un unico server (questo tipo di condivisione diventa tanto più efficace tanti più sono i Client connessi, in antitesi con la rete tradizionale Server/Client, dove un elevato numero di Client connessi riduce la velocità di trasmissione dati per utente);

• La sicurezza degli accessi ai client viene gestita localmente su ogni macchina e non centralizzata, questo significa che una rete basata su utenti deve avere lo stesso archivio reimpostato in ogni client.

In sintesi una rete basata sul P2P è una valida soluzione in tutti quegli ambiti dominati da problemi di scalabilità, che siano essi della rete come dei server.

1.4 – Impatto Socio-Economico del P2P

Come accennato il concetto di P2P è andato oltre alla semplice relazione tra computer, ma in modo molto più largo a qualsiasi relazione dinamica attiva in una rete distribuita, quindi anche tra esseri umani. Yochai Benkler ha coniato il termine “commons-based peer production” per indicare forme collaborative come i progetti opensource o Wikipedia. Assieme alla “peer production” sono nati i concetti di:

• peer governance (riferendosi a come i progetti “peer production” sono gestiti) • peer property (ovvero alle nuove licenze che riconoscono la paternità ad un individuo ma

non l'uso escusivo dei diritti, come la GNU GPL e le varie licenze Creative Commons )• peer distribution (il modo in cui i prodotti, in particolare i prodotti sviluppati dai peer sono

distribuiti)

Alcuni ricercatori hanno indagato sui benefici nelle comunità virtuali di auto-organizzazione e di incentivazione nella cooperazione e condivisione delle risorse sostenendo che l'aspetto sociale, ora assente dai sistemi P2P, dovrebbe essere un obbiettivo e un mezzo per creare e promuovere comunità virtuali auto-organizzate. Ricerche in corso stanno progettando meccanismi di incentivazione efficaci nei sistemi P2P; basate sui principi della teoria dei giochi stanno cominciando ad assumere una direzione più psicologica e di elaborazione delle informazioni.

5

Page 6: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

1.5 – Il Futuro del P2P

Accenno ora, ma verrà riproposto con maggior dettaglio nel capitolo successivo, il concetto di P2PTV. In futuro, le reti peer-to-peer potranno essere usate per diffondere elevati flussi di dati generati in tempo reale, come programmi televisivi o film. Questi programmi si basano sull'utilizzo delle banda di trasmissione di cui dispongono i singoli utenti e la banda viene utilizzata per trasmettere agli altri fruitori il flusso dati. Questa tipologia di programmi in linea di principio non richiede server dotati di elevate prestazioni, dato che il server fornisce i flussi video a un numero molto limitato di utenti, che a loro volta li ridistribuiscono ad altri utenti.

Questo metodo di diffusione permette in teoria la trasmissione in tempo reale di contenuti video, ma richiede che i singoli utenti siano dotati di connessioni ad elevata banda sia in ricezione che in trasmissione, altrimenti si arriverebbe rapidamente a una saturazione della banda fornita dal server.

Attualmente è improponibile la diffusione di una tale tecnologia in Italia, dove sono molto diffuse linee asimmetriche (ADSL) che forniscono una banda elevata in ricezione, ma scarsa in trasmissione.

Utilizzando questa tecnologia grandi società stanno sperimentando la possibilità di fornire contenuti a pagamento tramite tecnologie peer-to-peer. Questo scelta è motivata dal fatto che la tecnologia P2P non richiede server di grandi dimensioni per gestire molti utenti, dato che se la rete è ben bilanciata si autosostiene e quindi è indipendente dal numero di utenti. Vanno ancora risolti però problemi legati alla diffusione di materiali protetti dai diritti d'autore, e vi sono quindi, oltre agli inevitabili problemi di carattere tecnico, problemi di carattere legale e di affidabilità. Prima di lanciare servizi a livello nazionale vanno anche effettuate delle fasi di test per individuare eventuali anomalie o difetti; la diffusione su vasta scala di questa tipologia sembra quindi non essere imminente.

Sempre in merito al futuro del P2P, riagganciandosi al concetto che aveva Tim Berners-Lee di World Wide Web, non si può non accennare al progetto Osiris (Serverless Portal System).

Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi e distribuiti. I contenuti vengono scambiati tra i vari utenti tramite una rete P2P basata su Kademlia (un sistema P2P del tipo strutturato che sfrutta DHT) e poi salvati su ogni nodo che partecipa al portale, i dati sono scambiati tramite canali cifrati (AES) e i contenuti sono mantenuti anonimi in quanto non contengono alcun legame tra l'IP dell'autore e il suo account.

Sfruttando queste tecnologie anche se l'autore originario di un contenuto dovesse disconnettersi dalla rete i suoi contenuti sarebbero comunque accessibili senza alcun problema. Un altro vantaggio, probabilmente il più importante, è dato dall'assenza di un server centrale che consente di abbattere i costi di hosting e di non dover sottostare a policy restrittive dei provider.

Continuando in ambito informatico alcuni sviluppi del P2P prevedono la realizzazioni di reti telematiche che si affianchino alle reti tradizionali o che persino le sostituiscano. Un esempio di questi progetti è la rete Netsukuku, un sistema di routing sperimentale sviluppato dal FreakNet MediaLab, nato per costruire una rete distribuita, anonima e anarchica, non necessariamente separata da Internet, senza il supporto di alcun server, ISP e di alcuna autorità centrale.

C'è persino chi ha pensato che la rete Netsukuku possa essere utilizzata per a realizzazione di reti cellulari senza l'apporto di gestori telefonici. Questa applicazione parte dalla considerazione che gli algoritmi della rete richiedono ridotte risorse e quindi possono agevolmente girare sugli attuali cellulari, anche se per reali applicazioni in tal senso sono allo stato attuale solo teoriche.

Che siano comunque solo idee prettamente teoriche o progetti già avviati il concetto stesso di P2P

6

Page 7: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

ha dato avvio ad una vera e propria rivoluzione, in particolar modo in ambito informatico, sulla modalità di fruizione di servizi, fino a poco fa limitata dal concetto Client/Server.

2 – Lo Streaming in Internet

Vediamo ora lo Streaming via Internet. Iniziamo col dire cosa si intenda per “Streaming”.

Col termine Streaming si identifica un flusso di dati audio/video trasmessi da una sorgente a una o più destinazioni tramite una rete telematica. Questi dati vengono riprodotti man mano che arrivano a destinazione. Quindi non occorre attendere l'effettivo completamento del download per usufruire del file.

Per la trasmissione di tali flussi sono stati implementati e vengono tuttora usati vari metodi, ognuno con i suoi pregi e i suoi difetti:

• I protocolli di tipo datagram, l'User Datagram Protocol (UDP) in primis, inviano il flusso multimediale come una serie di piccoli pacchetti. Questo è un metodo semplice ed efficace, tuttavia non esiste un meccanismo all'interno del protocollo stesso che ne garantisce l'avvenuta consegna. E' compito dell'applicazione del ricevente identificare le perdite o i dati corrotti e recuperare i dati tramite tecniche di correzione degli errori. Se un dato è perso lo stream potrebbe soffrire di un “dropout”, ovvero di una momentanea interruzione.

• I Real-time Streaming Protocol (RTSP), Real-time Transport Protocol (RTP) e il Real-time Transport Control Protocol (RTCP) sono protocolli specificatamente designati per lo stream multimediale in rete. Mentre l'RTSP sfrutta vari protocolli di trasporto gli altri due sono costruiti direttamente sopra UDP.

• Un'altro approccio che sembra incorporare entrambi i vantaggi derivanti nell'usare uno protocollo web standard e la possibilità di poter essere usato anche per il live streaming è l'Adaptive Bitrate Streaming, si basa principalmente sul tipico download progressivo in HTTP, ma contrariamente all'approccio precedente, qui i file sono molto piccoli, così da essere paragonati allo streaming di pacchetti, similmente a RTSP e RTP.

• Protocolli come Transmission Control Protocol (TCP), garantiscono una consegna corretta di ogni singolo bit dello stream, tuttavia bisogna far fronte ad un sistema che prevede continui timeout e reinvii, il che lo rendono molto difficile da implementare. Ciò significa anche che quando un dato viene perso lo stream si interrompe mentre il protocollo individua la perdita e ritrasmette i dati mancanti. I Client possono minimizzare questo effetto bufferizzando i dati prima di farli visualizzare. Se tuttavia è accettabile un buffering per un video on demand, in altri scenari in cui avviene una interazione non è accettabile, basti pensare ad una video conferenza.

• I Protocolli Unicast mandano una copia separata dello stream multimediale dal server ad ogni ricevente, Unicast è la norma per la maggior parte delle connessioni Internet, ma non è molto scalabile quando molti utenti vogliono vedere lo stesso programma televisivo simultaneamente.

• I Protocolli Multicast sono stati sviluppati per ridurre il carico sia sul server che sulla rete risultante dai dati duplicati che vengono mandati a vari riceventi in una connessione Unicast. Questi protocolli inviano un singolo stream da una fonte a un gruppo di riceventi. A seconda della struttura della rete e dal tipo, le trasmissioni multicast possono o non possono essere fattibili. Un potenziale svantaggio del multicasting è l'assenza della possibilità di fornire video on demand. Un flusso continuo di materiale radio/televisivo preclude la capacità del destinatario di controllare la riproduzione. Tuttavia, questi problema possono essere mitigati da elementi come server di caching, set-top box digitali e media player con funzioni di

7

Page 8: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

buffer. • L'IP Multicast fornisce un mezzo per inviare un unico flusso multimediale a un gruppo di

destinatari su una rete di computer. Un protocollo multicast, di solito Internet Group Management Protocol, è usato per gestire l'erogazione di flussi multicast ai gruppi di destinatari su una LAN. Una delle sfide nell'implementazione di multicast IP è che i router e firewall tra le LAN devono consentire il passaggio di pacchetti destinati ai gruppi multicast. Se l'organizzazione che invia il contenuto ha il controllo sulla rete tra il server e i destinatari (ad esempio, istituti scolastici, governativi e intranet aziendali), poi possono essere usati protocolli di routing come Protocol Independent Multicast per fornire streaming di contenuti a vari segmenti di rete LAN.

• Ed infine il protocolli Peer-to-peer (P2P) che permettono l'invio del flusso tra i vari nodi della rete. In questo modo si evita che il server e le sue connessioni di rete diventino un collo di bottiglia. L'uso di tali protocolli solleva però problemi di tipo tecnico, di prestazioni, di qualità e di diritti.

A lato pratico si può portare l'esempio di Youtube. Essa è un celebre esempio di piattaforma che fornisce una moltitudine di video on demand (e particolari eventi anche live) in streaming video. Dei protocolli descritti precedentemente Youtube utilizza l'HTTP per fornire lo stream ai suoi utenti. E' innegabile dunque che con un tale numero di utenti connessi contemporaneamente sia necessario sovradimensionare il server (distribuirlo) e sia necessaria una grande banda in rete, con il rischio di congestionarla, come detto in precedenza. Questo problema affligge tutti i metodi sopra descritti, dall'invio tramite UDP al Multicast. Lo sviluppo di protocolli Peer-to-Peer affidabili per lo streaming quindi risolverebbe di molto le varie difficoltà di tipo logistico e dei costi nei quali incorrono oggi i fornitori di servizi di streaming live e on demand.

Volendo si possono fare alcuni conti per dare delle cifre su quanto possa essere impattante un protocollo piuttosto che un altro. Prendiamo delle connessioni Unicast, che richiedono connessioni multiple dal server, come scritto prima, anche quando gli stream hanno lo stesso contenuto.

La dimensione di un flusso multimediale è determinato dalla sua durata e dal bitrate utilizzato:

Dimensioni (in megabytes) = durata (in secondi) × bitrate (in bit/s) / (8 × 1024 × 1024)

Esempio:

Un'ora di filmato codificato a 300 kbit/s (accettabile per un video con una finestra di risoluzione di 320 × 240 pixels, fino a qualche anno fa la norma su un sito di streaming come Youtube)

(3600 s × 300.000 bit/s) / (8×1024×1024) richiede 128 MB.

Se tale file è fornito per lo streaming on-demand ed è visto simultaneamente da 1000 persone utilizzando un protocollo Unicast occorrono

300 kbit/s × 1000 = 300.000 kbit/s = 300 Mbit/s di banda.

Equivale a 135 GB l'ora. Usando un protocollo multicast si manda uno stream comune a tutti gli utenti, quindi il server utilizzerà solo 300 kbit/s.

Calcolo simile per gli eventi Live.

Se la velocità dell'encoder è di 500 kbit/s e l'evento dura 3 ore con 3000 utenti allora:

Numero di MB inviati = velocità dell'encoder (in bit/s) × durata (in secondi) × numero di spettatori / (8*1024*1024)

8

Page 9: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

Numero di MB inviati = 500 x 1024 (bit/s) × 3 × 3600 ( = 3 ore) × 3000 (spettatori) / (8*1024*1024) = 1.977.539 MB.

2.1 – La TV nel Web.

Soprattutto negli ultimi anni si è sviluppata l'idea di fornire servizi di tipo televisivo utilizzando la rete. Del resto solamente pensando ai costi ci si rende conto di quanto sia facile una distribuzione dei contenuti utilizzando Internet; grazie alla rete mondiale inoltre le emittenti sono raggiungibili in tutto il mondo grazie a questo tipo di servizio, quindi possono andare ben oltre le emittenti tradizionali. Esistono principalmente due sistemi: le IPTV e le WebTV.

Il sistema IPTV è generalmente usato per diffondere i contenuti audiovisivi attraverso connessioni ad Internet a banda larga. È tecnologicamente distinto dalla Web TV in quanto mentre quest'ultima è realizzata attraverso una comunicazione best-effort, l'IPTV è realizzata con meccanismi di trasmissione che ne garantiscano la qualità di servizio (QoS) a favore dell'utente attraverso meccanismi tipici di priorità.

L'IPTV è stato visto da molti come un settore che potrà avere in futuro una forte diffusione, di pari passo con la disponibilità della banda larga.

Da un lato l'IPTV offre delle potenzialità tecnologiche quali il Video on Demand rispetto alle distribuzioni televisive tradizionali come la televisione analogica terrestre, il digitale terrestre, il satellite e, nei paesi in cui viene usata, la TV via cavo, ma contemporaneamente propone un modello chiuso, dove il provider decide quali contenuti e in quali modalità debbano essere fruiti dagli utenti.

L'utente Internet, al quale il servizio IPTV dovrebbe essere rivolto, è invece abituato a scegliere sul web e sugli altri servizi della rete a quali contenuti accedere e in quali modalità.

Fino ad ora l'IPTV poteva vantare una certa supremazia sulla WebTV per qualità tecnologica, ma ormai quest'ultima, offerta sia da servizi appositi quali YouTube o Vimeo, che da singoli siti più o meno grandi, ha quasi raggiunto la stessa qualità video, senza contare la quantità di contenuti e le modalità di accesso che la rendono molto più adatta all'utente Internet.

Consideriamo inoltre il File Sharing via P2P che, nonostante i problemi legali, continua a crescere rappresentando di fatto un'alternativa all'acquisto degli stessi contenuti offerti dall'IPTV.

2.2 – La P2P TV come Evoluzione della WebTV

I due sistemi sopra menzionati ovvero l'IPTV e la WebTV sono due sistemi basati sulla ormai consolidata concezione Client/Server, ma vari progetti vogliono sfruttare la tecnologia P2P per la condivisione dello streaming ai vari utenti, una sorta di evoluzione della WebTV, la cosiddetta P2P TV.

La peculiarità di questa tecnologia è che basandosi sull'utilizzo di reti peer-to-peer non servono necessariamente server di elevate capacità per trasmettere i flussi video dato che i suddetti flussi vengono ritrasmessi dagli stessi utilizzatori della rete secondo il paradigma del peer-to-peer di cui ho già scritto . Quindi non deve essere un server centrale a trasmettere tutti i flussi video, il server trasmette il flusso video a un certo numero di utenti, questi a loro volta ritrasmettono il flusso video ad altri utenti generando una rete che può raggiungere anche milioni di utilizzatori. Il programma installato dall'utente si occupa di rintracciare e scaricare, tra gli altri utenti, i pezzi che mancano e di

9

Page 10: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

inviare quelli in proprio possesso ad altri. Il video viene ovviamente riprodotto con alcuni secondi di ritardo per permettere al numero maggiore possibile di peer di scaricare tutti i pezzi del filmato.

Da segnalare l'idea del gruppo P2P-Next con il software SwarmPlayer (un plugin per Firefox e Internet Explorer), attualmente applicato sul portale di VoDo che permette la visione di contenuti sfruttando lo swarm dei nodi della rete Bittorrent e il Tag HTML5 <video> , quindi il tentativo di creare una P2P TV appoggiandosi su una rete già esistente e solida, già utilizzata da milioni di persone in tutto il mondo.

Analizziamo ora i vantaggi di una rete di trasmissione audiovisiva basata sul P2P:

• Il metodo di distribuzione peer-to-peer ottimizza il flusso di dati verso gli utenti, questo permette nel caso di reti con molti utenti di massimizzare le informazioni trasmesse all'utente a differenza delle strutture client-server che all'aumento degli utenti induce un degradamento dei singoli dati trasmessi agli utenti.

• Studi hanno dimostrato che le reti peer-to-peer generano la maggior parte del loro traffico all'interno delle reti dei singoli Internet Service Provider e quindi questi non vedono un notevole aumento dei costi di interconnessione tra Internet Service Provider.

• Le reti peer-to-peer non richiedendo grandi infrastrutture, permettendo la nascita di reti dedicate che raggruppano utenti che ricercano contenuti simili.

Ed ora gli svantaggi:• Le reti peer-to-peer non garantiscono la qualità di servizio a differenza delle reti client-

server unicast che possono fissare una banda minima per ogni utente. Le reti peer-to-peer basano il loro funzionamento sul corretto funzionamento dei computer dei singoli utenti, quindi degli utenti con una connessione lenta o con un computer lento possono degradare le prestazioni del sistema.

• Le reti peer-to-peer generano fino al 40% di dati in più rispetto a una trasmissione unicast. Per ridurre il problema della mancanza di qualità del servizio le reti peer-to-peer indirizzano più flussi video verso lo stesso utente, in questo modo si migliora il servizio ma si aumentano le informazioni ridondanti nella rete. Inoltre trasmissioni multicast permettono a un solo flusso di raggiungere più utenti contemporaneamente e quindi un'efficienza ancora maggiore.

• Le reti televisive tradizionali trasmettono alcuni contenuti in alcuni stati e/o regioni, questo può essere facilmente realizzato con una rete client-server ma è molto più difficile da realizzare, o sarebbe meglio dire “controllare”, in una rete peer-to-peer.

• Le reti peer-to-peer scaricano parte dei costi di trasmissione sui singoli utenti. Questo può essere un problema per alcuni utenti ADSL che pur potendo ricevere molti dati ne possono trasmettere una quantità relativamente ridotta e quindi non possono essere dei buoni utenti di una rete peer-to-peer.

3 – Come Realizzare un'Applicazione di Streaming P2P

Come ho già introdotto nei capitoli precedenti un sistema di streaming P2P è un sistema in cui ogni nodo client può svolgere la funzione di server, quindi un ottimo sistema se si intendono risolvere problemi di scalabilità sia sulla rete che sul carico dei server che verrebbero implicati in una comune connessione Client/Server.

Prima di tutto quindi per realizzare un'applicazione di streaming P2P bisogna realizzare un overlay appropriato, le soluzioni sono tante, si vedano strutture tipo rete a maglie (mesh) oppure nodi distribuiti ad albero. In tutti i casi comunque sono necessarie funzioni che permettano la scoperta di

10

Page 11: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

altri nodi, e altre che permettano l'effettiva realizzazione di questo overlay. Un'altra questione cruciale è come mettere in comunicazione i nodi, come possono scambiarsi informazioni di vario genere: sapere di che frammento video hanno bisogno, chi ha effettivamente il frammento necessario, sapere com'è strutturata la rete, chi è il nodo più vicino.

Si deve quindi anche considerare i protocolli di trasporto, senza i quali sarebbe impossibile una comunicazione: come già scritto nel Capitolo 2 la scelta di una connessione di tipo TCP piuttosto che una di tipo UDP comporta notevoli implicazioni sulle prestazioni dello streaming, bisogna quindi valutare a seconda delle situazioni cosa sia più opportuno.

In alcuni casi le informazioni necessarie ai nodi sono implicite, per esempio in una struttura ad albero ogni nodo sa chi può fornirgli il frammento, ovvero il padre, e a chi inviarlo, i suoi figli, ma ci sono altri casi in cui ciò non è così semplice, si pensi appunto ad una rete mesh, nella quale scoprire i nodi “prossimi” è cruciale per l'efficienza della rete.

Realizzare un sistema per lo streaming P2P comporta dunque l'utilizzo di vari funzioni fondamentali a seconda dell'applicazione e del tipo di overlay che si vuole implementare; creare tali funzioni dal nulla, o persino rielaborarne di nuove a seconda delle varie situazioni che sorgono nel corso di un progetto possono sottrarre molto lavoro allo sviluppatore. Lo scopo della libreria GRAPES è proprio quello di fornire al programmatore le primitive necessarie allo streaming P2P permettendogli di dedicarsi maggiormente sull'applicazione che vuole creare.

.

3.1 – La Libreria GRAPES

Come dichiara la HomePage del progetto, GRAPES è una libreria che mira a fornire agli sviluppatori una serie di funzioni per la costruzione di applicazioni di streaming P2P: peer sampling, chunk scheduling, scambio di buffermaps, invio e ricezione di chunk e molto altro. In questo senso GRAPES può essere visto come una serie di blocchi di costruzione per permettere facilmente lo sviluppo di applicazioni anche molto complesse.

GRAPES è implementata come una libreria C e può essere direttamente utilizzata da altre applicazioni in C o C++, e anche da applicazioni scritte in altri linguaggi con gli adeguati accorgimenti.

Attualmente GRAPES offre le seguenti funzionalità:

• Un network helper, che permette agli sviluppatori di costruire applicazioni P2P senza curarsi del protocollo di trasporto impiegato. Attualmente è disponibile un net helper basato sul protocollo UDP.

• Un meccanismo di peer sampling.• Un'astrazione Peer Set, che permette la costruzione di topologie di rete complesse e

strutturate.• Un tipo di dato Chunk Buffer, che implementa un buffer temporizzato dove un'applicazione

di streaming può archiviare i chunk ricevuti. Attualmente l'implementazione è sfruttabile da applicazioni per lo streaming in diretta, visto che i chunk vengono rimossi automaticamente dal buffer una volta che diventano obsoleti.

• Un tipo di dato Chunk ID Set, che permette ai peer di scambiarsi informazioni sui chunk in loro possesso o di cui hanno bisogno. Questo tipo di dati è alla base dei vari meccanismi di segnale, e provvede ad alcune funzioni di codifica dei contenuti di un chunk id set in un messaggio da distribuire nella rete.

• Un meccanismo di Chunk trading, che permette l'incapsulamento di chunk in un messaggio

11

Page 12: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

e della loro distribuzione nella rete senza il bisogno che l'applicazione si preoccupa di altro.

Come mostrerò nei capitoli successivi è possibile sfruttando le funzioni offerte da GRAPES per la realizzazione di un semplice software che permette la creazione di una rete P2P e la conseguente distribuzione di un flusso video attraverso tutti i nodi della rete.

3.2 – La topologia della rete: la struttura ad Albero

Uno degli overlay più semplici da realizzare è probabilmente quello ad albero.

Una struttura ad albero è la struttura dati che si riconduce al concetto di albero con radice presente nella teoria dei grafi. Un albero si compone di due tipi di sottostrutture fondamentali: il nodo, che in genere contiene informazioni, e l'arco che stabilisce un collegamento gerarchico fra due nodi: si parla allora di un nodo padre dal quale esce un arco orientato che lo collega ad un nodo figlio. Si chiede inoltre che ogni nodo possa avere al massimo un unico arco entrante, mentre dai diversi nodi possono uscire diversi numeri di archi uscenti. Si chiede infine che l'albero possegga un unico nodo privo di arco entrante: questo nodo viene detto radice (root) dell'albero. Ogni nodo che non presenta archi uscenti, è detto foglia (leaf node); e in ogni albero finito, cioè con un numero finito di nodi, si trova almeno un nodo foglia. Ovviamente, un nodo può essere contemporaneamente padre (se ha archi uscenti) e figlio (se ha un arco entrante, ovvero se è diverso dalla radice).

Applicando tutto questo al P2P vediamo subito che la radice è il nodo che diffonderà inizialmente lo streaming multimediale, gli archi sono le connessioni che si instaurano tra i nodi, mentre i vari client sono appunto i vari nodi dell'albero che invieranno a loro volta lo stream ai loro figli.

Se vogliamo possiamo catalogare una simile struttura nella categoria dei sistemi P2P centralizzati, ovvero in quei particolari sistemi strutturati che non possono funzionare senza la presenza di un supernodo che assolve particolari funzioni.

Salta però subito all'occhio la debolezza di una struttura simile nel P2P: se un nodo cessa l'attività di peer interrompe lo streming su un intero sottoalbero.

Nell'immagine, che rappresenta una possibile struttura ad albero, se il nodo 3 interrompe ogni tipo di comunicazione i due nodi figli (4,5) non riceveranno più alcun dato.

Si può comunque fare in modo che l'intera struttura si riconfiguri a causa della scomparsa di un nodo: un esempio è quello che ogni nodo del sottoalbero interessato ricontatti la radice per la

12

Page 13: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

riassegnazione in un nuovo sottoalbero, infatti uno metodo per la creazione della struttura è quello di delegare al supernodo la gestione dell'albero dirottando i nuovi nodi in arrivo verso i nodi disponibili, in tal caso la radice dovrebbe tenere in memoria in qualche modo una mappa dell'intera rete oppure ancor più semplicemente procedere a scatola chiusa, ovvero, nel caso non si possa accettare un nodo come figlio, metterlo a conoscenza dei propri figli attualmente connessi, in questo modo il nuovo nodo cercherà ricorsivamente un possibile padre.

Una cosa necessaria è anche che l'albero che viene a formarsi sia bilanciato, sempre per mantenere il carico su tutti i nodi minimo e equilibrato. Ciò può essere implementato in vari modi, con vari algoritmi.

4 – Applicazione per lo Streaming P2P

Vediamo ora effettivamente il codice di una possibile applicazione per lo Streaming P2P sviluppata per mezzo della libreria GRAPES.

Nell'esempio che mi accingo a presentare la struttura assumerà una semplice forma di albero binario bilanciato, con il termine binario intendo dire che ogni nodo avrà al più 2 figli, il supernodo non creerà l'intera mappa della rete, ma come ho precedentemente spiegato si limiterà ad accettare i peer, o in caso contrario reindirizzarli verso i propri figli, così come faranno anche gli altri peer.

Entrambi i tipi di nodo avranno due processi, un processo padre che si occuperà dell'invio e ricezione dei dati e un processo figlio che si occuperà dell'accettazione o reindirizzamento dei nodi in arrivo.

4.1 – Analisi del Codice

Innanzitutto analizziamo alcuni frammenti, i più importanti, del codice del supernodo, o seeder, la cui principale differenza con gli altri nodi è quella che non deve ricevere un file, ma prelevare un file in input e metterlo a disposizione degli altri nodi. All'avvio il supernodo prende in ingresso 2 parametri, il primo è la porta su cui girerà l'intera applicazione, il secondo parametro invece è un file video da mettere in condivisione.

./seeder <porta> <input file>

Fondamentale è la creazione della socket, ciò viene fatto utilizzando alcune funzioni fornite da GRAPES, con le quali si crea l'identificatore del nodo.

static struct nodeID *

init (int port)

{

struct nodeID *myID;

myID = net_helper_init (my_addr, port, "");

if (myID == NULL)

13

Page 14: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

{

fprintf (stderr, "Error creating my socket (%s:%d)!\n", my_addr, port);

return NULL;

}

chunkDeliveryInit (myID);

return myID;

}

Una volta che è stata inizializzata la socket si avviano 2 processi, un processo padre che invia i chunk agli eventuali figli, e un processo figlio che si occupa dell'accettazione dei nodi, se il seeder ha già dei figli restituisce al nodo richiedente i due nodi figli perché li contatti per la ricerca di un nodo padre. I due processi condividono una memoria cosicché il processo padre sappia sempre il numero e chi sono i nodi figli per l'invio dei chunk.

In questo esempio, come avevo già accennato, i possibili figli sono limitati a 2, quindi viene creato un albero binario.

Vedendo più nel dettaglio il codice del processo figlio si vede come esso resti in loop e utilizzi la funzione recv_from_peer messa a disposizione dalla libreria GRAPES per l'ascolto. Nel caso arrivi un messaggio da un peer ne ricava le informazioni (IP e porta) con nodeid_undump, dopo di che risponde con un messaggio di accettazione (HALLO) o di rinuncia (LIST) con la funzione send_to_peer. Se un figlio viene accettato viene aggiunto alla struct figli, e alla memoria condivisa, altrimenti invia al nodo le informazioni sui nodi figli.

Da notare come i nodi memorizzati non abbiano la porta così come si sono annunciati al seeder, ma che il valore è aumentato di 1, questo sarà più chiaro osservando il codice dei nodi client, sinteticamente i nodi client, facendo sia la funzione di server che di client, usano 2 porte, per semplicità la porta di valore X viene utilizzata per la comunicazione verso gli altri nodi e per ricevere i chunk, mentre la porta X+1 per la ricezione delle comunicazioni di altri nodi.

if (pid == 0)

{

printf ("Sono in attesa di Figli...\n");

while (!fatto)

{

res = recv_from_peer (my_sock, &remote, buff, BUFFSIZE);

if (res > 0)

{

remote = nodeid_undump (buff, &dimensioni);

printf ("UnDump Avvenuto\n");

node_ip (remote, ip, BUFFSIZE);

printf ("IP Sorgente: %s\n", ip);

14

Page 15: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

if (num_figli == 0)

{

mess = "HALLO";

res = send_to_peer (my_sock, remote, mess, BUFFSIZE);

node_ip (remote, buf_tmp, BUFFSIZE);

tmp = create_node (buf_tmp, node_port (remote) + 1);

nodeid_dump (figli.figlio_uno, tmp, BUFFSIZE);

num_figli++;

(*a).n_children++;

nodeid_dump ((*a).buf, remote, BUFFSIZE);

printf ("Figlio Accettato\n");

}

else if (num_figli == 1)

{

mess = "HALLO";

res = send_to_peer (my_sock, remote, mess, BUFFSIZE);

node_ip (remote, buf_tmp, BUFFSIZE);

tmp = create_node (buf_tmp, node_port (remote) + 1);

nodeid_dump (figli.figlio_due, tmp, BUFFSIZE);

(*a).n_children++;

nodeid_dump ((*a).buf + 16, remote, BUFFSIZE);

num_figli++;

printf ("Figlio Accettato\n");

}

else

{

mess = "LIST";

res = send_to_peer (my_sock, remote, mess, BUFFSIZE);

send_to_peer (my_sock, remote, figli.figlio_uno, BUFFSIZE);

send_to_peer (my_sock, remote, figli.figlio_due, BUFFSIZE);

}

15

Page 16: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

}

else

printf ("Errore\n");

}

}

Il processo padre si occupa invece dell'invio dello stream ai figli, purché siano effettivamente presenti. Tramite la memoria condivisa il processo verifica la presenza di figli, se il loro numero è maggiore di 0 procede con l'invio dei chunk.

Importante è la funzione chunkise che commuta l'input in chunk da inviare. Tali chunk devono comunque essere inviati con un ritmo predefinito in base al bitrate dello stream video. Tutto ciò viene fatto grazie alla funzione “attesa” basandosi su un ritardo calcolato sull'attuale ora del sistema e del valore di timestamp del chunk che va inviato (tale valore di timestamp è calcolato dalla libreria basandosi sul bitrate e dalla dimensione del pacchetto inviato). Infine, sempre tramite la memoria condivisa il processo invia il chunk al/ai figli(o) dei quali è venuto a conoscenza con il processo figlio. Da notare che l'invio dei chunk non è fatto con la funzione send_to_peer, utilizzata in precedente per lo scambio di messaggi tra peer, ma con una funzione ad hoc chiamata sendChunk.

Ovviamente dobbiamo anche prendere in considerazione alla fine del file di inviare ai nodi figli un segnale per annunciargli la fine dello stream e la conseguente chiusura del programma, per questo viene inviato un chunk particolare, qui nominato “end” con id=0. Dal lato client sarà impostato che l'arrivo di un chunk con id = 0 comporta la fine dello stream e del programma.

id = 1;

n_chunk = 0;

while (!done)

{

nf = (*a).n_children;

if (nf > 0)

{

int res, att;

c.id = id;

c.attributes_size = 0;

res = chunkise (input, &c);

if (res > 0)

{

gettimeofday (&now, NULL);

if (id == 1)

16

Page 17: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

time_zero = now.tv_sec * 1000000ULL + now.tv_usec;

time_n = time_zero + c.timestamp;

att = time_n - (now.tv_sec * 1000000ULL + now.tv_usec);

if (nf == 2)

{

fi_uno = nodeid_undump ((*a).buf, &len);

fi_due = nodeid_undump ((*a).buf + 16, &len);

sendChunk (fi_uno, &c, 0);

sendChunk (fi_due, &c, 0);

}

else if (nf == 1)

{

fi_uno = nodeid_undump ((*a).buf, &len);

sendChunk (fi_uno, &c, 0);

}

id++;

attesa (att);

}

else if (res < 0)

{

end.id = 0;

end.timestamp = 1000000000ULL;

end.size = strlen ("end") + 1;

end.data = strdup ("end");

end.attributes_size = 0;

if (nf == 2)

{

fi_uno = nodeid_undump ((*a).buf, &len);

fi_due = nodeid_undump ((*a).buf + 16, &len);

sendChunk (fi_uno, &end, 0);

sendChunk (fi_due, &end, 0);

}

else if (nf == 1)

17

Page 18: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

{

fi_uno = nodeid_undump ((*a).buf, &len);

sendChunk (fi_uno, &end, 0);

}

printf ("Chunk di fine inviato.... Fine.\n");

done = 1;

}

free (c.data);

}

}

Come detto occorre una funzione “attesa” per la sincronizzazione. Per farlo si usa una funzione della libreria GRAPES, la “wait4data”. Siccome la funzione prende in ingresso un parametro timeval occorrono delle piccole accortezze, come mostrato nel codice. Per calcolare il parametro k, ovvero i microsecondi di attesa, viene semplicemente eseguito un calcolo sommando il tempo di invio del primo chunk segnato dal sistema con il tempo indicato dal timestamp del chunk. Sottraendo infine a questa somma il tempo attuale in cui si sta inviando il determinato chunk si ha il tempo di attendere prima dell'invio. Questo valore in microsecondi viene poi aggiunto ad una struttura timeval e quindi eseguita la funzione “wait4data”.

void

attesa (int k)

{

int micro = k;

struct timeval req;

req.tv_sec = 0;

req.tv_usec = micro;

wait4data (NULL, &req, NULL);

}

Vediamo ora come funziona il nodo client, qui nominato “leecher”.

Il programma prende in ingresso 4 parametri. L'IP del nodo da contattare, la porta su cui contattarlo, la porta sui cui il programma stesso deve girare e il file di output.

./leecher <host> <host port> <client port> <output file>

In questo caso, essendo una semplice dimostrazione, i chunk vengono scritti in output e non riprodotti tramite un player, tuttavia è possibile riprodurre il file anche prima dell'effettivo completamente.

18

Page 19: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

Per quanto riguarda il codice le differenze con il seeder si concentrano nel processo padre, e nella presenza di una struttura coda, anch'essa fornita dalla libreria, tale coda è necessaria per la creazione di una struttura ad albero bilanciata. Finché il nodo non trova un padre immette i figli ricevuti dagli altri nodi in un coda, quindi una gestione FIFO. In tal modo si garantisce il bilanciamento dell'albero.

fifo_queue_p q;

[….]

q = fifo_queue_create (2000);

dst_ip = argv[1];

printf ("Porta Remota: %d\n", atoi (argv[2]));

dst = create_node (dst_ip, atoi (argv[2]));

err = fifo_queue_add (q, dst);

il primo nodo da contattare che viene aggiunto alla coda è il nodo fornito in input al programma.

In seguito avviene la divisione tra processo padre e figlio, mentre il processo figlio è praticamente identico a quello già visto nel codice del seeder, il codice del processo padre cambia considerevolmente.

Da notare tuttavia che vengono create 2 socket, una utilizzata dal processo padre per ricevere e mandare i chunk, l'altra dal processo figlio per comunicare con potenziali nodi figli.

my_sock = init (atoi (argv[3]));

my_s_sock = init (atoi (argv[3]) + 1);

Nel processo padre si preleva il valore alla testa della coda, il quale viene contattato. Se la risposta è un HALLO significa che si è stati accettati come nodo figlio, in tal caso si interrompe il loop di ricerca. In caso contrario, quindi si è ricevuto il messaggio di LIST, allora si rimuove il valore di testa dalla coda e si resta in ascolto la ricezione dei due nodi figli, i quali vengono aggiunti alla coda e il loop di ricerca continua. Nel caso venga trovato un nodo padre si procede con la funzione di ricezione dei chunk.

while (!done)

{

rem = fifo_queue_get_head (q);

node_ip (rem, ip, BUFFSIZE);

printf ("IP Destinazione: %s\n", ip);

printf ("Porta Destinazione: %d\n", node_port (rem));

nodeid_dump (mio_ip, my_sock, BUFFSIZE);

check = send_to_peer (my_sock, rem, mio_ip, BUFFSIZE);

19

Page 20: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

if (check > 0)

{

printf ("Messaggio inviato\n");

check = recv_from_peer (my_sock, &rem, buff, BUFFSIZE);

if (check > 0)

{

printf ("%s\n", buff);

if (strcmp (buff, "HALLO") == 0)

{

my_seed = rem;

node_ip (my_seed, ip, BUFFSIZE);

printf ("Ho trovato una fonte! %s\n", ip);

done = 1;

}

else

{

if (strcmp (buff, "LIST") == 0)

{

fifo_queue_remove_head (q);

recv_from_peer (my_sock, &rem, buff, BUFFSIZE);

rec = nodeid_undump (buff, &len);

err = fifo_queue_add (q, rec);

printf ("Ricevuto primo figlio!\n");

recv_from_peer (my_sock, &rem, buff, BUFFSIZE);

printf ("Ricevuto secondo figlio!\n");

rec = nodeid_undump (buff, &len);

err = fifo_queue_add (q, rec);

printf ("Dimensioni della Coda: %d\n",

fifo_queue_size (q));

}

else

printf ("Messaggio Sconosciuto.\n");

}

}

else

20

Page 21: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

printf ("Errore nella Ricezione.\n");

}

else

printf ("Messaggio non inviato.\n");

}

printf ("In attesa dei Chunk da %s ....\n", ip);

ricezione (my_sock, my_seed, output, shmid);

La funzione ricezione prende in ingresso 4 parametri: la socket sulla porta X, quella fornita nei parametri del programma, l'identificatore del nodo padre, il file di output e l'id della memoria condivisa, questo per sincronizzarsi col processo figlio e sapere quindi se bisogna inviare chunk ad eventuali figli acquisiti nel frattempo. La funzione resta in ascolto sulla porta, ricevuto un chunk lo decodifica, poi, se ha dei figli, invia anche a loro il chunk, poi scrive il chunk su output e continua in loop, questo finché non riceve un chunk di fine, ovvero un chunk con id = 0, in tal caso significa che lo stream è concluso e il programma si interrompe.

void

ricezione (my_sock, my_seed, output, shmid)

{

int done_again = 0;

uint8_t buffer[BUFFSIZE];

struct nodeID *fi_uno;

struct nodeID *fi_due;

struct chunk c;

struct shared_data *dat = shmat (shmid, NULL, SHM_RND);

while (!done_again)

{

int ser, nf, len = 16;

nf = (*dat).n_children;

ser = recv_from_peer (my_sock, &my_seed, buffer, BUFFSIZE);

decodeChunk (&c, buffer + 1 + 2, ser);

if (nf == 2)

{

fi_uno = nodeid_undump ((*dat).buf, &len);

fi_due = nodeid_undump ((*dat).buf + 16, &len);

sendChunk (fi_uno, &c, 0);

sendChunk (fi_due, &c, 0);

21

Page 22: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

}

else if (nf == 1)

{

fi_uno = nodeid_undump ((*dat).buf, &len);

sendChunk (fi_uno, &c, 0);

}

if (c.id != 0)

{

chunk_write (output, &c);

}

else

{

printf ("Ricezione dello Stream completata.\n");

done_again = 1;

}

}

nodeid_free (fi_uno);

nodeid_free (fi_due);

out_stream_close (output);

printf ("Fine.\n");

}

4.2 – Implementazioni Future

I programmi seeder e leecher sono due ottimi esempi delle potenzialità fornite da GRAPES allo sviluppatore, ma non possono assolumente definirsi programmi pronti per l'utente finale.

Ciò che salta subito all'occhio è che i chunk vengono scritti in output e non riprodotti come ci si aspetterebbe da un programma per lo streaming, e, cosa forse più importante, non viene fatto alcun controllo sulla connessione dei peer una volta agganciati come figli o come padri. Come spiegato nel capitolo 3.2 in una struttura ad albero è fondamentale gestire eventuali disconnessioni volontarie o meno dei peer se non si vuole che interi sottoalberi restino privati dello stream.

22

Page 23: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

Bibliografia

Rüdiger Schollmeier, A Definition of Peer-to-Peer Networking for the Classification of Peer-to-Peer Architectures and Applications, Proceedings of the First International Conference on Peer-to-Peer Computing, IEEE (2002).

Shen, Xuemin; Yu, Heather; Buford, John; Akon, Mursalin (2009). Handbook of Peer-to-Peer Networking (1st ed.).

P. Antoniadis and B. Le Grand, "Incentives for resource sharing in self-organized communities: From economics to social psychology," Digital Information Management (ICDIM '07), 2007

Andreucci Giacomo, YouTube. Video online e Web TV, Edizioni FAG, Milano, 2012

Serafini Domenico , La Televisione via Internet: una nuova frontiera, Video Age, 1999

Link Utili

HomePage del Progetto GRAPES:

http://imedia.disi.unitn.it/P2PStreamers/grapes.html

Codice Completo

Fornisco qui di seguito il codice completo delle due applicazioni: seeder.c e leecher.c

----------- SEEDER.C --------------

#include <stdlib.h>

#include <stdint.h>

#include <stdio.h>

#include <string.h>

#include <getopt.h>

#include <inttypes.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/ipc.h>

23

Page 24: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

#include <sys/shm.h>

#include <time.h>

#include "net_helper.h"

#include "chunk.h"

#include "trade_msg_la.h"

#include "trade_msg_ha.h"

#include "net_helpers.h"

#include "grapes_msg_types.h"

static char in_opts[1024];

static const char *my_addr = "127.0.0.1";

const int *in_fds;

#define BUFFSIZE 4000

struct figli

{

uint8_t figlio_uno[BUFFSIZE];

uint8_t figlio_due[BUFFSIZE];

};

//struttura per i dati condivisi tra processo padre e processo figlio

struct shared_data

{

int n_children;

uint8_t buf[50];

};

static struct nodeID *

init (int port)

{

struct nodeID *myID;

myID = net_helper_init (my_addr, port, "");

if (myID == NULL)

{

fprintf (stderr, "Error creating my socket (%s:%d)!\n", my_addr, port);

return NULL;

}

chunkDeliveryInit (myID);

return myID;

}

24

Page 25: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

void

attesa (int k)

{

int micro = k;

struct timeval req;

req.tv_sec = 0;

req.tv_usec = micro;

wait4data (NULL, &req, NULL);

}

int

main (int argc, char *argv[])

{

uint8_t buff[BUFFSIZE];

struct nodeID *my_sock;

struct nodeID *remote;

struct nodeID *tmp;

struct nodeID *fi_uno;

struct nodeID *fi_due;

struct figli figli;

int num_figli = 0;

uint8_t ip[BUFFSIZE + 1];

uint8_t *mess;

uint8_t buf_tmp[BUFFSIZE];

int res, dimensioni = 4000, len = 16, period, pid, nf, shmid;

int id, n_chunk, time_zero, time_n = 0;

struct chunk end;

struct chunk c;

struct timeval now;

struct input_stream *input;

int fatto = 0, done = 0;

my_sock = init (atoi (argv[1]));

input = input_stream_open (argv[2], &period, in_opts);

if (input == NULL)

{

fprintf (stderr, "Cannot open input %s\n", argv[2]);

return -1;

}

if (period == 0)

{

in_fds = input_get_fds (input);

}

25

Page 26: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

else

{

in_fds = NULL;

}

//creazione memoria condivisa

printf ("Sto per creare la memoria condivisa\n");

shmid = shmget (IPC_PRIVATE, 4000, 0666);

if (shmid == -1)

{

printf ("errore creazione memoria\n");

exit (0);

}

else

printf ("prelevata memoria id = %d\n", shmid);

// struttura condivisa

struct shared_data *a = (struct shared_data *) shmat (shmid, NULL, SHM_RND);

// fork

pid = fork ();

//processo figlio che si occupa delle accettazioni dei peer

if (pid == 0)

{

printf ("Sono in attesa di Figli...\n");

while (!fatto)

{

res = recv_from_peer (my_sock, &remote, buff, BUFFSIZE);

if (res > 0)

{

printf ("Messaggio Dump: %s\n", buff);

remote = nodeid_undump (buff, &dimensioni);

printf ("UnDump Avvenuto\n");

node_ip (remote, ip, BUFFSIZE);

printf ("IP Sorgente: %s\n", ip);

if (num_figli == 0)

{

mess = "HALLO";

res = send_to_peer (my_sock, remote, mess, BUFFSIZE);

printf ("%d\n", res);

node_ip (remote, buf_tmp, BUFFSIZE);

tmp = create_node (buf_tmp, node_port (remote) + 1);

nodeid_dump (figli.figlio_uno, tmp, BUFFSIZE);

num_figli++;

(*a).n_children++;

nodeid_dump ((*a).buf, remote, BUFFSIZE);

26

Page 27: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

printf ("Figlio Accettato\n");

}

else if (num_figli == 1)

{

mess = "HALLO";

res = send_to_peer (my_sock, remote, mess, BUFFSIZE);

printf ("%d\n", res);

node_ip (remote, buf_tmp, BUFFSIZE);

tmp = create_node (buf_tmp, node_port (remote) + 1);

nodeid_dump (figli.figlio_due, tmp, BUFFSIZE);

(*a).n_children++;

nodeid_dump ((*a).buf + 16, remote, BUFFSIZE);

num_figli++;

printf ("Figlio Accettato\n");

}

else

{

mess = "LIST";

res = send_to_peer (my_sock, remote, mess, BUFFSIZE);

printf ("%d\n", res);

send_to_peer (my_sock, remote, figli.figlio_uno, BUFFSIZE);

send_to_peer (my_sock, remote, figli.figlio_due, BUFFSIZE);

}

}

else

printf ("Errore\n");

}

}

//il processo padre invia lo stream ai figli (se presenti)

id = 1;

n_chunk = 0;

while (!done)

{

nf = (*a).n_children;

//se ho dei figli inizio l'invio

if (nf > 0)

{

int res, att;

c.id = id; //setto l'id del chunk

c.attributes_size = 0; // setto la dimensione degli attibuti, obbligatorio impostarlo.

res = chunkise (input, &c);

if (res > 0)

{

27

Page 28: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

gettimeofday (&now, NULL);

if (id == 1)

time_zero = now.tv_sec * 1000000ULL + now.tv_usec;

time_n = time_zero + c.timestamp;

att = time_n - (now.tv_sec * 1000000ULL + now.tv_usec);

/* calcolo il tempo all'invio del primo chunk,

time_n è uguale al tempo zero più il timestamp del chunk

l'attesa sarà quindi la differenza tra il tempo n e il tempo attuale

*/

// invio del chunk

//caso figli = 2

if (nf == 2)

{

fi_uno = nodeid_undump ((*a).buf, &len);

fi_due = nodeid_undump ((*a).buf + 16, &len);

sendChunk (fi_uno, &c, 0);

sendChunk (fi_due, &c, 0);

}

//caso figli = 1

else if (nf == 1)

{

fi_uno = nodeid_undump ((*a).buf, &len);

sendChunk (fi_uno, &c, 0);

}

id++; // incremento dell'id

attesa (att); // effettua l'attesa

}

//chunk di fine

else if (res < 0)

{

end.id = 0;

end.timestamp = 1000000000ULL;

end.size = strlen ("end") + 1;

end.data = strdup ("end");

end.attributes_size = 0;

//caso figli =2

if (nf == 2)

{

fi_uno = nodeid_undump ((*a).buf, &len);

fi_due = nodeid_undump ((*a).buf + 16, &len);

sendChunk (fi_uno, &end, 0);

sendChunk (fi_due, &end, 0);

28

Page 29: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

}

//caso figli = 1

else if (nf == 1)

{

fi_uno = nodeid_undump ((*a).buf, &len);

sendChunk (fi_uno, &end, 0);

}

printf ("Chunk di fine inviato.... Fine.\n");

//fine degli invii, fine del programma.

done = 1;

}

free (c.data);

}

}

//libero la memoria

nodeid_free (my_sock);

nodeid_free (remote);

nodeid_free (tmp);

return 0;

}

----------- LEECHER.C --------------

#include <unistd.h>

#include <stdio.h>

#include <stdint.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

#include <time.h>

#include <string.h>

#include <getopt.h>

#include <inttypes.h>

#include "net_helper.h"

#include "net_helpers.h"

#include "grapes_msg_types.h"

#include "fifo_queue.h"

#include "chunk.h"

#include "trade_msg_la.h"

#include "trade_msg_ha.h"

29

Page 30: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

#define BUFFSIZE 4000

static const char *my_addr = "127.0.0.1";

static char *dst_ip;

const int *in_fds;

char *b_string;

static char out_opts[1024];

//creo la struct nei quali archivio i nodi figli

struct figli

{

uint8_t figlio_uno[BUFFSIZE];

uint8_t figlio_due[BUFFSIZE];

};

//struttura per i dati condivisi tra processo padre e processo figlio

struct shared_data

{

int n_children;

uint8_t buf[50];

};

//creo la struct figli di tipo figli, poca fantasia.

struct figli figli;

//funzione per inizializzare il nodo

static struct nodeID *

init (int port)

{

struct nodeID *myID;

myID = net_helper_init (my_addr, port, "");

if (myID == NULL)

{

fprintf (stderr, "Error creating my socket (%s:%d)!\n", my_addr, port);

return NULL;

}

chunkDeliveryInit (myID);

return myID;

}

// Funzione per la ricezione dal nodo padre

void

ricezione (my_sock, my_seed, output, shmid)

{

int done_again = 0;

int n_chunk = 0;

uint8_t buffer[BUFFSIZE];

struct nodeID *fi_uno;

30

Page 31: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

struct nodeID *fi_due;

struct chunk c;

struct shared_data *dat = shmat (shmid, NULL, SHM_RND);

while (!done_again)

{

int ser, nf, len = 16;

nf = (*dat).n_children;

ser = recv_from_peer (my_sock, &my_seed, buffer, BUFFSIZE); //arrivo dei chunks

decodeChunk (&c, buffer + 1 + 2, ser); //decodifica dei chunk arrivati

//verifico il numero dei figli, se ho dei figli gli invio il chunk

//caso figli = 2

if (nf == 2)

{

fi_uno = nodeid_undump ((*dat).buf, &len);

fi_due = nodeid_undump ((*dat).buf + 16, &len);

sendChunk (fi_uno, &c, 0);

sendChunk (fi_due, &c, 0);

}

//caso figli = 1

else if (nf == 1)

{

fi_uno = nodeid_undump ((*dat).buf, &len);

sendChunk (fi_uno, &c, 0);

}

//verifico l'ID del chunk arrivato

//se l'id è diverso da 0 significa che non è un chunk di fine file

if (c.id != 0)

{

n_chunk++; //incremento dei chunks arrivati, più per fini di debug

chunk_write (output, &c); // scrittura sull'output

}

//altrimenti è un chunk di fine

else

{

printf ("Ricezione dello Stream completata.\n");

done_again = 1;//imposto done_again = 1, fine del while, fine connessione

}

}

nodeid_free (fi_uno);

nodeid_free (fi_due);

out_stream_close (output);

31

Page 32: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

printf ("Fine.\n");

}

//main

int

main (int argc, char *argv[])

{

//dichiarazioni

fifo_queue_p q;

int err, done, fatto = 0, res, check = 0, len = 4000;

struct nodeID *my_sock;

struct nodeID *my_s_sock;

struct nodeID *dst;

struct nodeID *rem;

struct nodeID *my_seed;

struct nodeID *rec;

struct nodeID *remote;

struct nodeID *tmp;

uint8_t ip[BUFFSIZE];

uint8_t mio_ip[BUFFSIZE];

uint8_t buff[BUFFSIZE];

uint8_t buf_tmp[BUFFSIZE];

uint8_t *mess;

int num_figli = 0;

int pid;

int shmid;

struct output_stream *output;

//creazione memoria condivisa

printf ("Sto per creare la memoria condivisa\n");

shmid = shmget (IPC_PRIVATE, 4000, 0666);

if (shmid == -1)

{

printf ("errore creazione memoria\n");

exit (0);

}

else

printf ("prelevata memoria id = %d\n", shmid);

//apertura stream output

output = out_stream_init (argv[4], out_opts);

if (output == NULL)

{

fprintf (stderr, "Cannot open output %s\n", argv[4]);

32

Page 33: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

return -1;

}

//inizializzazioni

q = fifo_queue_create (2000);

dst_ip = argv[1];

printf ("Porta Remota: %d\n", atoi (argv[2]));

dst = create_node (dst_ip, atoi (argv[2]));

err = fifo_queue_add (q, dst);

my_sock = init (atoi (argv[3]));

my_s_sock = init (atoi (argv[3]) + 1);

// struttura condivisa

struct shared_data *a = (struct shared_data *) shmat (shmid, NULL, SHM_RND);

// fork

pid = fork ();

//processo figlio che si occupa delle accettazioni dei peer

if (pid == 0)

{

while (!fatto)

{

res = recv_from_peer (my_s_sock, &remote, buff, BUFFSIZE);

if (res > 0)

{

printf ("Messaggio Dump: %s\n", buff);

remote = nodeid_undump (buff, &len);

printf ("UnDump Avvenuto\n");

node_ip (remote, ip, BUFFSIZE);

printf ("IP Sorgente: %s\n", ip);

if (num_figli == 0)

{

mess = "HALLO";

res = send_to_peer (my_s_sock, remote, mess, BUFFSIZE);

printf ("%d\n", res);

node_ip (remote, buf_tmp, BUFFSIZE);

tmp = create_node (buf_tmp, node_port (remote) + 1);

nodeid_dump (figli.figlio_uno, tmp, BUFFSIZE);

num_figli++;

(*a).n_children++;

nodeid_dump ((*a).buf, remote, BUFFSIZE);

}

else if (num_figli == 1)

{

mess = "HALLO";

res = send_to_peer (my_s_sock, remote, mess, BUFFSIZE);

33

Page 34: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

printf ("%d\n", res);

node_ip (remote, buf_tmp, BUFFSIZE);

tmp = create_node (buf_tmp, node_port (remote) + 1);

nodeid_dump (figli.figlio_due, tmp, BUFFSIZE);

(*a).n_children++;

nodeid_dump ((*a).buf + 16, remote, BUFFSIZE);

num_figli++;

}

else

{

mess = "LIST";

res = send_to_peer (my_s_sock, remote, mess, BUFFSIZE);

printf ("%d\n", res);

send_to_peer (my_s_sock, remote, figli.figlio_uno, BUFFSIZE);

send_to_peer (my_s_sock, remote, figli.figlio_due, BUFFSIZE);

}

}

else

printf ("Errore\n");

}

}

//il processo padre si occupa del contatto con la sorgente

while (!done)

{

rem = fifo_queue_get_head (q);

node_ip (rem, ip, BUFFSIZE);

printf ("IP Destinazione: %s\n", ip);

printf ("Porta Destinazione: %d\n", node_port (rem));

node_ip (my_sock, mio_ip, BUFFSIZE);

printf ("IP Mittente: %s\n", mio_ip);

nodeid_dump (mio_ip, my_sock, BUFFSIZE);

check = send_to_peer (my_sock, rem, mio_ip, BUFFSIZE);

if (check > 0)

{

printf ("Messaggio inviato\n");

check = recv_from_peer (my_sock, &rem, buff, BUFFSIZE);

if (check > 0)

{

printf ("%s\n", buff);

if (strcmp (buff, "HALLO") == 0)

{

34

Page 35: Federico Bertolini - Inventati Bertolini_Realizzanzione di... · Osiris, così come il suo predecessore KeyForum, utilizza una rete peer-to-peer per dar vita a portali web anonimi

my_seed = rem;

node_ip (my_seed, ip, BUFFSIZE);

printf ("Ho trovato una fonte! %s\n", ip);

done = 1;

}

else

{

if (strcmp (buff, "LIST") == 0)

{

fifo_queue_remove_head (q);

recv_from_peer (my_sock, &rem, buff, BUFFSIZE);

rec = nodeid_undump (buff, &len);

err = fifo_queue_add (q, rec);

printf ("Ricevuto primo figlio!\n");

recv_from_peer (my_sock, &rem, buff, BUFFSIZE);

printf ("Ricevuto secondo figlio!\n");

rec = nodeid_undump (buff, &len);

err = fifo_queue_add (q, rec);

printf ("Dimensioni della Coda: %d\n",

fifo_queue_size (q));

}

else

printf ("Messaggio Sconosciuto.\n");

}

}

else

printf ("Errore nella Ricezione.\n");

}

else

printf ("Messaggio non inviato.\n");

}

printf ("In attesa dei Chunk da %s ....\n", ip); // messaggio in attesa dei chunks

ricezione (my_sock, my_seed, output, shmid); //ricezione dei chunk

//libero la memoria

nodeid_free (my_sock);

nodeid_free (my_s_sock);

nodeid_free (dst);

nodeid_free (tmp);

nodeid_free (my_seed);

nodeid_free (rec);

return 0;

}

35