Instant Peer-to-Peer Media Streaming for Use in Multi-party

Werbung
Instant peer-to-peer media streaming
for use in multi-party conferencing
- Masterarbeit –
Institut für Softwaretechnik und Datenkommunikation
Hochschule Mannheim
Paul-Wittsack-Straße 10
68163 Mannheim
Autor:
Matr.-Nr.:
Studiengang:
Lyubomir Lyubenov
0710894
Informationstechnik
Betreuer:
Prof. Dr. Eckhart Körner, Hochschule Mannheim
Dipl. -Ing. Lothar Grimm, T-Systems ES GmbH, Darmstadt
Ehrenwörtliche Erklärung
Ich versichere, dass ich die vorliegende Arbeit selbständig und ohne Benutzung
anderer als der angegebenen Hilfsmittel angefertigt habe. Alle Stellen, die wörtlich
oder sinngemäß aus veröffentlichten und nicht veröffentlichten Schriften entnommen
wurden, sind als solche kenntlich gemacht. Die Arbeit hat in dieser oder ähnlicher
Form keiner anderen Prüfungsbehörde vorgelegen.
Mannheim, den 24.02.2009
Lyubomir Lyubenov
Abstrakt
Application Layer Multicast (ALM) ist eine Technik, die in den letzten Jahren immer
mehr an Bedeutung gewonnen hat. Sie basiert auf Peer-To-Peer (P2P)
Kommunikation. Eine von vielen auf ALM basierenden Anwendungen ist das Video
Streaming, auch in der Form als Live-Übertragung.
Diese Arbeit beschäftigt sich zunächst mit ALM und den zugrunde liegenden P2PNetzen. Die existierenden Ansätze für P2P-Netze werden eingeführt und nach ihren
Architekturen klassifiziert. Des Weiteren wird eine freie Implementierung eines P2PProtokolls namens Pastry vorgestellt, speziell mit ihrer Erweiterung SplitStream.
SplitStream bietet eine API, die den Aufbau eines ALM für Live Video Streaming
ermöglicht. Für die Medienübertragung kann dabei das Real-time Transport Protocol
(RTP) eingesetzt werden.
Weiterer Schwerpunkt dieser Arbeit ist das multi-party Conferencing mit dem SIPProtokoll, welches die Signalisierung für die Audio- und Videokommunikation unter
mehreren Endnutzern zur Verfügung stellt.
Der praktische Teil dieser Arbeit befasst sich mit der Implementierung eines Plugins
für den SIP User Agent (UA) SIP Communicator, welcher unter der GNU GPL Lizenz
steht. Der SIP Communicator wird in Java entwickelt und setzt auf das dynamische
Java Modulsystem OSGi auf, welches eine Service-Orientierte Programmierung
ermöglicht.
Die Aufgabe des für den SIP Communicator entwickelten Plugins ist der Aufbau
eines ALM auf Basis von SplitStream, welches ein Live Video Streaming unter den
Nutzern in einer multi-party Conference ermöglicht. Dafür wurde auch die SIPSignalisierung des UAs erweitert, um SIP-basierte Konferenzgespräche zu
unterstützen. Beispielszenarien für die Nutzung von P2P Live Video Streaming in
Konferenzen sind das Einspielen eines Urlaubvideos oder die Live-Übertragung
eines Popkonzerts in eine bestehende SIP Session. Derartige Szenarien werden in
den aktuellen Conferencing Tools noch gar nicht unterstützt.
Abschließend werden die Ergebnisse analysiert und die weiterführenden Aufgaben
definiert.
Abstract
In the past few years Application Layer Multicast (ALM) gained more and more
importance. Peer-to-peer (p2p) networks catalyse the importance of this new
technology. There are different applications based on ALM. One of them is live video
streaming.
In this master thesis, we describe at first the p2p technology. Then we classify the
different p2p networks depending on their architecture. We work with a free p2p
protocol called Pastry and its extension SplitStream. SplitSteam provides a
programming API for the establishment of an ALM. We also consider the Real-time
Transport Protocol (RTP) protocol which defines a standardized packet format for
delivering audio and video over the Internet. Next, we describe the Session Initiation
Protocol (SIP) protocol that is widely used for setting up and tearing down multimedia
communication sessions such as voice and video conferences over the Internet.
The practical part of this thesis deals with the implementation of a plug-in for a SIP
User Agent (UA). We use the SIP Communicator (SC) that is an audio/video Internet
phone and instant messenger. It supports some of the most popular instant
messaging and telephony protocols such as SIP, Jabber and ICQ. The SIP
Communicator is Open Source Software, and is freely available under the terms of
the GNU Lesser General Public License. SC works with the Java-based service
platform OSGi. Thus, we also provide a small introduction to service-oriented
programming.
The new SC plug-in can be deployed to construct an ALM based on SplitStream. The
UAs will then be able to distribute videos in a live mode among the participants in a
conference. Our example scenario is the multicasting of a holiday video or a rock
concert within a SIP session. Thereby, we want to demonstrate a future use of p2p
video streaming. This use case is a major highlight of the thesis as there is no
implementation yet of this feature in any current instant messenger.
In the conclusion we discuss the obtained results and possible future works.
Inhaltsverzeichnis
1. Einführung.............................................................................................................................. 6
1.1 Motivation ........................................................................................................................ 6
1.2 Zielsetzung ....................................................................................................................... 6
1.3 Überblick der Kapitel ....................................................................................................... 7
2. Technologischer Hintergrund................................................................................................. 8
2.1 SIP (Session Initiation Protocol) ...................................................................................... 8
2.2 SDP (Session Description Protocol) .............................................................................. 11
2.3 RTP (Realtime Transport Protocol) ............................................................................... 12
2.4 Peer-to-Peer-Netze ......................................................................................................... 13
2.4.1 Einführung............................................................................................................... 13
2.4.2 Klassifizierung ........................................................................................................ 14
2.5 Peer-To-Peer-Netze für Live Video Streaming.............................................................. 17
2.5.1 Einführung............................................................................................................... 17
2.5.2 Baumbasierte Systeme ............................................................................................ 18
2.5.3 Vermaschte Systeme ............................................................................................... 22
2.6 OSGi - Dynamic Module System for Java..................................................................... 24
2.6.1 Einführung............................................................................................................... 24
2.6.2 Die OSGi Service Plattform.................................................................................... 24
2.6.3 Implementierungen.................................................................................................. 25
2.6.4 Das OSGi Framework ............................................................................................. 25
2.6.5 Grundelemente ........................................................................................................ 26
3. Konzept ................................................................................................................................ 28
3.1 SIP-basierte Konferenz mit Live Video Streaming........................................................ 28
3.2 Das P2P Konzept............................................................................................................ 32
3.2.1 Hashfunktionen ....................................................................................................... 32
3.2.2 Pastry....................................................................................................................... 34
3.2.3 Scribe....................................................................................................................... 37
3.2.4 SplitStream .............................................................................................................. 39
3.3 Das OSGi-Schichtenmodell ........................................................................................... 41
3.3.1 Module-Schicht ....................................................................................................... 42
3.3.2 Die Lifecycle-Management-Schicht ....................................................................... 43
3.3.3 Die Service-Schicht................................................................................................. 44
3.3.4 Die Security-Schicht ............................................................................................... 44
3.3.5 Die Framework Services ......................................................................................... 45
4. Realisierung.......................................................................................................................... 46
4.1 Erstellen eines SplitStream Clients ................................................................................ 46
4.2 Entwicklung eines OSGi Pugins .................................................................................... 57
4.3 Erstellen von eigenen Modulen für den SIP Communicator.......................................... 62
4.4 SplitStream Erweiterungen für den SIP Communicator ................................................ 66
4.4.1 P2P-Live-Video-Streaming-Proxy .......................................................................... 66
4.4.2 Anbindung an den SIP Communicator.................................................................... 68
5. Zusammenfassung................................................................................................................ 74
5.1 Ergebnisse ...................................................................................................................... 74
5.1 Weiterführende Aufgaben .............................................................................................. 74
Anhang A: Use Case für Integration von SplitStream mit SIP ................................................ 76
Anhang B: Abbildungsverzeichnis........................................................................................... 81
Anhang C: Listingverzeichnis.................................................................................................. 82
Anhang D: Literaturverzeichnis ............................................................................................... 83
1. Einführung
1. Einführung
1.1 Motivation
Im Zeitalter von Web 2.0 werden immer neue Onlinedienste angeboten. Das VideoSharing wird immer beliebter, nicht nur bei Jugendlichen, sondern auch bei
Erwachsenen. In den meisten Fällen ruft ein Nutzer eine entsprechende Webseite
auf und schaut sich ein eingebettetes Video an. Er ist dabei mehr oder minder
passiv, es fehlt das Gemeinschaftserlebnis. Man wünscht sich daher eine
Möglichkeit, Videos und Musik mit anderen zu teilen und zwar in Echtzeit. Die
Tauschbörsen bieten keine echte Alternative, da man dort abwarten muss, bis die
Media-Datei heruntergeladen ist.
Aktuell existieren ausgereifte Peer-to-Peer (P2P) Netze. Die zugrunde liegende
Technologie wird immer intelligenter, angefangen bei hybriden P2P Netzen, bei
denen ein Server vorhanden ist, um bestimmte Aufgaben zu erfüllen, bis hin zu
reinen P2P-Architekturen, wo die Clients alle Funktionen erbringen. Andererseits
stehen Internet-Protokolle wie SIP zur Verfügung, um die Audio- und
Videokommunikation zwischen Onlinenutzern zu vermitteln.
Es sollte von daher möglich sein, die unterschiedlichen Technologien in einem
einzigen Produkt zu vereinen, so dass das gemeinsame Anschauen eines Videos
während einer Audio- bzw. Videokonferenz stattfinden kann. Damit werden Leute
von geografisch entfernten Regionen näher aneinander gebracht, um ihre Videos,
aber auch Gefühle besser auszutauschen.
1.2 Zielsetzung
Ziel dieser Masterarbeit ist es, einen existierenden SIP User Agent für die
Unterstützung von Media Streaming zu erweitern. Als Beispielszenarien dienen das
Einspielen eines Urlaubvideos oder die Live-Übertragung eines Popkonzerts in eine
bestehende SIP Session. Dabei kann es sich um eine SIP Session mit zwei oder
mehr Teilnehmern handeln. Zur effizienten Medienverteilung in einer großen Gruppe
wird ein Application Layer Multicast (Peer-to-Peer Video Streaming) eingesetzt.
Ausgangspunkt für die Implementierung ist der als Open Source von der Universität
Straßbourg entwickelte Instant Messenger „SIP Communicator“ (SC), und speziell
seine Erweiterung zur Unterstützung des SIP Protokolls. Der SIP Communicator ist
in Java entwickelt und setzt auf das dynamische Java Modulsystem OSGi auf. Der
IM Client ist in zweierlei Hinsicht zu erweitern:
•
Erweiterung der SIP Signalisierung für Konferenzen mit beliebiger Anzahl
Teilnehmer.
-6-
1. Einführung
•
Integration des VLC Media Players mit Peer-to-Peer Proxy. Ein Peer-to-Peer
Live Video Streaming System wurde bereits in einer vorherigen Masterarbeit
entwickelt. [thr]
1.3 Überblick der Kapitel
Dieses Dokument soll dem Leser als Erstes einen Überblick über die Peer-To-Peer Technologie und Overlay-Netze für Live Video Streaming geben. Zusätzlich werden
die Protokolle für die Übertragung von Medienströmen im Internet eingeführt. Das
zweite Kapitel beginnt mit der Beschreibung der Media-Protokolle SIP, SDP und
RTP, die die Basis für eine Audio- bzw. Videokommunikation bilden. Anschließend
werden die P2P-Netze klassifiziert. Schließlich wird die service-orientierte Architektur
OSGi mit ihren Grundbausteinen vorgestellt. Sie spielt bei der nachfolgenden
Implementierung eine wichtige Rolle.
Im Kapitel 3 liegt der Fokus auf der Entwicklung einer geeigneten SIP Signalisierung
für Live Video Streaming in Konferenzen. Dazu werden auch die Pastry-Technologie
und die aus ihr stammenden Weiterentwicklungen Scribe und SplitStream näher
beschrieben. Schließlich wird das OSGi – Schichtenmodell weiter ausgebaut.
Kapitel 4 widmet sich der Java-Implementierung des Konzeptes aus Kapitel 3. Es
wird gezeigt, wie man einen SplitStream Client und ein OSGi Bundle erstellen kann.
Zusätzlich wird die Schnittstelle des SIP Communicators für die Entwicklung eigener
Module betrachtet. Mit Hilfe dieser Kenntnisse werden am Ende des Kapitels die am
SIP Communicator vorgenommenen Erweiterungen beschrieben.
Zum Abschluss werden in Kapitel 5 die erreichten Ergebnisse zusammengefasst und
der Ausblick auf weitere Entwicklungen gegeben.
-7-
2. Technologischer Hintergrund
2. Technologischer Hintergrund
In diesem Kapitel werden Technologien und Protokolle beschrieben, die P2P Video
Streaming ermöglichen. An erster Stelle werden SIP und SDP vorgestellt, die zum
Aufbau, zur Steuerung und zum Abbau einer Kommunikationssitzung zwischen zwei
oder mehr Teilnehmern eingesetzt werden. Kapitel 2.3 führt das Real-Time Transport
Protocol (RTP) ein, welches zur kontinuierlichen Übertragung von audiovisuellen
Daten (Streams) über IP-basierte Netzwerke benutzt wird. Anschließend werden die
Techniken der P2P-Netze analysiert und nach ihrer Struktur klassifiziert. Als logische
Fortsetzung werden die unterschiedlichen Topologien für P2P Live Video Streaming
Netze betrachtet. Auf Basis ihrer Vor- und Nachteile werden die aktuellen Trends auf
diesem Gebiet herausgearbeitet. Abschließend wird die OSGi Service Plattform mit
ihren Grundelementen vorgestellt.
2.1 SIP (Session Initiation Protocol)
Das Session Initiation Protocol (SIP) ist ein Netzwerkprotokoll zum Aufbau einer
Kommunikationssitzung zwischen zwei und mehr Teilnehmern. Das Protokoll wird in
den RFC 3261 [r1] (früher RFC 2543 [r2]) spezifiziert. Im Gegensatz zu H.323, das
von der ITU-T stammt, wurde SIP mit Blick auf das Internet von der IETF entwickelt
und orientiert sich an der Architektur gängiger Internet – Anwendungen. Dabei wurde
von Beginn an auf leichte Implementierbarkeit, Skalierbarkeit, Erweiterbarkeit und
Flexibilität geachtet.
SIP kann benutzt werden, um beliebige Sessions mit einem oder mehreren
Teilnehmern zu verwalten. Dabei ist es nicht auf Internet – Telefonie beschränkt,
sondern Sessions können beliebige Multimediaströme, Konferenzen, Computerspiele
usw. sein. [Wiki]
Mit Hilfe des SIP-Protokolls werden die Initialisierungen der Verbindung
vorgenommen sowie Daten und Parameter der Verbindung ausgetauscht. SIP ähnelt
sehr dem HTTP Protokoll, denn es ist ASCII – formatiert und unterteilt die Art der
Nachrichtenübermittelung in Requests (aktive Anfragen) und Responses (passive
Antworten auf Anfragen). Bei Request – Anfragen steht die Art der Anforderung in
der ersten Zeile. Es gibt folgende Request Typen:
•
INVITE — Lädt einen anderen Client zu einem Gespräch ein
•
ACK — Bestätigt den Verbindungsaufbau und leitet somit den
Gesprächsbeginn ein
•
BYE — Beendet die aktuelle Sitzung
•
OPTIONS — Dient zur Ermittlung von Benutzer- und Serverdaten, wird jedoch
nicht für den Aufbau benötigt
•
CANCEL — Wird vorwiegend von Servern oder Proxies zum Signalisieren
eines Abbruches verwendet
-8-
2. Technologischer Hintergrund
•
REGISTER — Damit meldet sich der SIP-Teilnehmer am SIP-Server oder SIP
Proxy an. Häufig wird hier eine verschlüsselte Benutzer – Authentifizierung
nach dem ”MD5 – Hash“- Verfahren vorgenommen
•
INFO — Dient zum Transport beliebiger Informationen in der Payload der SIP
– Nachricht. Die durch das SDP eingestellten Parameter werden dadurch nicht
beeinflusst. Häufig werden XML- Dateien zur Statuskontrolle oder Steuerung
übertragen
•
MESSAGE — Dient der Realisierung eines Instant Messengers, der Chat –
Nachrichten sofort überträgt und anzeigt
•
PRACK — Dient der vorläufigen Bestätigung einer wichtigen Response
Nachricht der 100er Reihe
•
SUBSCRIBE — Signalisiert dem SIP – Server, SIP – Proxy oder SIP – Client,
dass der Benutzer über eine bestimmte Status – Änderung informiert werden
möchte. Beispiel hierfür ist die Presence – Funktion des Instant Messengers,
welche Auskunft darüber erteilt, ob ein Benutzer gerade online oder
beschäftigt ist
•
Notify — Ist die oben beschriebene Mitteilung, dass sich ein Status geändert
hat. Häufig wird hier ein XML – File angehängt, das den neuen Status
beschreibt
•
UNSUBSCRIBE — Löscht die Statusbenachrichtigung wieder
Die Response-Nachrichten werden in Form eines dreistelligen Zahlencodes in der
ersten Headerzeile zurückgegeben. Die Festlegung entspricht weitgehend der des
HTTP – Protokolls:
•
100 - 199 — Vorläufige Bestätigung, mit dem Ziel den Request – Steller auf
ein bestimmtes Ereignis warten zu lassen. Gebräuchlichstes Beispiel ist die
”180 – Ringing“ Response. Sie signalisiert dem Anrufer, dass die Gegenstelle
klingelt.
•
200 - 299 — Bestätigung des Requests. Die ”200 – OK“ Response ist hier die
Standard Antwort.
•
300 - 399 — Umleitung. Der Client sollte die vom Server neu übermittelte
Adresse benutzen.
•
400 - 499—Client Fehler. Die ”404-Not found“ Response ist auch aus der
www – Welt bekannt. Die Fehlermeldung wird ausgegeben, wenn die
angegebene SIP – URL nicht in eine IP-Adresse aufgelöst werden kann.
•
500 - 599 — Server Fehler. Diese Error-Response zeigt häufig einen Ausfall
oder Absturz der Software an. Die ”508-Not implemented“ - Response besagt,
dass der Client den Request nicht bearbeiten kann, da diese Funktion noch
-9-
2. Technologischer Hintergrund
nicht implementiert ist (z.B. wenn ein SIP-Client eine Instant Message an ein
älteres SIP – Phone schickt).
Die antwortende Response-Nachricht enthält weitgehend dieselben Parameter, wie
der aufrufende Request (sh. Abb. 2-1).
Abbildung 2 - 1: Kommunikation über SIP
Besonders wichtig ist die Adressierung der Endgeräte (im Nachfolgenden Client
genannt) über email-ähnliche Adressen der Form ”sip:[email protected]“. Dabei
spielt es keine Rolle, ob sich die IP – Adresse des Clients ändert, denn bei dem Start
und in regelmäßigen Zeitabständen muss der Client sich bei seinem zuständigen SIP
– Provider registrieren. Der Provider betreibt für die Namens-/ Adressumsetzung
hierzu einen so genannten SIP – Proxy, der unter der entsprechenden Domain rund
um die Uhr verfügbar ist. Die Clients schicken ihre Anfragen an den Proxy, der diese
dann an die entsprechenden Gegenstellen weiterleitet. Man unterscheidet zwischen
”Stateless“- und ”Statefull“ – Proxies. Erstere realisieren hauptsächlich die oben
beschriebene Adressumsetzung. Die ”Statefull“ - Proxy-Server merken sich
zusätzlich für jede Verbindung zwischen den Clients den aktuellen Status der
Sitzung. Dadurch ist es möglich, die getätigte Verbindung und deren Dauer zu
protokollieren, um so eventuell eine Kostenabrechnung zu realisieren.
- 10 -
2. Technologischer Hintergrund
Abbildung 2 - 2: Verbindungsaufbau mit Proxy Server
Zu beachten ist bei der oben gezeigten Abbildung 2-2, dass die eigentlichen
Sprachdaten im RTP – Protokoll nicht über den SIP - Proxy laufen, sondern direkt,
d.h. ”peer to peer“, übertragen werden.
2.2 SDP (Session Description Protocol)
Das zuvor erwähnte SIP-Protokoll überträgt selbst keine verbindungsspezifischen
Parameter, wie zum Beispiel das verwendete Internet-Protokoll, IP-Addresse, Port
und die zur Verfügung stehenden Audio- / Video-Codecs. Es fügt hierfür das Session
Description Protocol (SDP) in die eigene Payload ein.
Auch das SDP-Protokoll ist ASCII formatiert, die Parameter werden durch
Abkürzungen eingeleitet:
•
v — Protokollversion
•
o — Absender und Session-Identifier
•
s — Session-Name
•
t — Medienzeitstempel
•
m — Medienname und –adresse
- 11 -
2. Technologischer Hintergrund
•
i — Session-Information
•
u — URI der Session
•
e — Emailadresse
•
p — Telefonnummer
•
b — Bandbreiten-Informationen
•
z — Zeitzonen-Einstellungen
•
k — Chiffrierungsschlüssel
•
a — Session Attribut
Sollte es während einer aufgebauten Kommunikation zur Veränderung der Audio- /
Video-Codecs kommen, so ist es im SIP Protokoll vorgesehen, dass man eine ReINVITE Nachricht verschicken kann, die in ihrem SDP Header die neuen
Verbindungsparameter enthält. Es ist wichtig anzumerken, dass der Call-ID
Parameter im SIP Header unverändert bleibt. Die Call-ID stellt die eindeutige
Zuordnung eines SIP-Kommunikationselements zu einer bestimmten Session dar.
Alle Nachrichten und Statusinformationen, die eine bestimmte Session betreffen,
tragen dieselbe Call-ID, die mindestens aus einem vom Session-Initiator generierten
Zufallscode besteht. [sip]
2.3 RTP (Realtime Transport Protocol)
Das Realtime Transport Protocol (RTP) wurde von der Audio-Video Transport Group
der IETF entwickelt und ist Bestandteil von H.323. Es liegt auf der
Anwendungsschicht und kann netzwerkbasierte Video- oder Audiokommunikation
abwickeln (sh. Abb. 2-3). Zur Unterscheidung der Medien unterscheidet RTP
zwischen verschiedenen Codierungsformaten, sodass die übertragenen Daten
anwendungsunabhängig verwendet werden können. Für diesen Zweck wurden
verschiedene RTP-Profile für Audio und Video definiert.
- 12 -
2. Technologischer Hintergrund
Abbildung 2 - 3: RTP im TCP/IP-Protokollstapel
Das RTP-Protokoll ist unabhängig von den darunter liegenden Protokollen, es wird in
der Regel mit dem UDP-Protokoll betrieben, wobei die RTP-Datenpakete in die UDPDatenpakete eingepackt werden.
Das RTP-Protokoll basiert auf einer Ende-zu-Ende-Verbindung und unterstützt
Unicast-Verbindungen, aber auch IP-Multicast. Es erkennt und korrigiert fehlende,
doppelte oder in falscher Reihenfolge empfangene Datenpakete. Im RTP-Header
existieren neben diversen Datenfeldern für die Version und das Padding zwei
Datenfelder für die eindeutige Identifizierung der Datenquellen und der
Quelladressen. Die Statusinformationen der Quellen werden durch das RTCPProtokoll, das Bestandteil von RTP ist, durch periodisches Senden rückgemeldet.
[itw]
2.4 Peer-to-Peer-Netze
2.4.1 Einführung
Peer-to-Peer-Netzwerke erfreuen sich immer größerer Beliebtheit. Ständig werden
neue Anwendungen auf dieser Basis entwickelt. Das Internet bietet einen großen
Vorrat an Ressourcen, sowohl in Form von Speicherplatz, als auch an
Rechenleistung. Es ist möglich, mit Hilfe von Peer-to-Peer-Netzwerken solche
Ressourcen zu teilen, genauso wie sie zu vereinen. Datenmessungen sagen voraus,
dass das Datentransfervolumen solcher Anwendungen stark steigt und einen sehr
wesentlichen Teil des Internetverkehrs ausmacht.
- 13 -
2. Technologischer Hintergrund
Peer-to-Peer bedeutet Kommunikation unter Gleichen. Das heißt, dass solche
Netzwerke im Gegensatz zum heute aktuellen Client/Server-Prinzip stehen (sh Abb.
2-4), bei dem Server Dienste anbieten, die von Clients genutzt werden. Ein Beispiel
dafür sind Webserver und die auf Nutzerseite installierten Browser. In einem Peer-toPeer Netzwerk ist prinzipiell jeder Knoten gleich und nimmt die Rolle eines Servers,
eines Clients und eines Routers an, der Nachrichten weiterleitet. Dafür wird ein
Overlay-Netzwerk gebildet, das über der bestehenden Infrastruktur eines
Netzwerkes, zum Beispiel des Internets, aufgebaut wird.
Abbildung 2 - 4: Client/Server Verbindungsprinzip
2.4.2 Klassifizierung
Man unterscheidet drei Arten von Peer-to-Peer Netzwerken:
•
Zentralisiert: Es gibt zentrale Server (sh. Abb. 2-5), die die Kommunikation
steuern. Beispielsweise bei Napster wurden die Verzeichnisinhalte der Knoten auf
solchen Servern gespeichert. Anfragen von Knoten wurden von diesen
Maschinen bearbeitet und entsprechende Ergebnisknoten mit gewünschtem
Inhalt zurückgeliefert.
- 14 -
2. Technologischer Hintergrund
Abbildung 2 - 5: Zentralisierte P2P-Architektur
•
Strukturiert, dezentralisiert: In solchen Systemen existieren keine zentralen
Server mehr, jedoch herrscht eine bestimmte vordefinierte Netzwerkstruktur vor
(sh. Abb. 2-6). In dieser Struktur werden Dateien an bestimmten Orten platziert,
um Anfragen besser bearbeiten zu können. Solche Systeme sind beispielsweise
Distributed Hash Tables (DHT) wie Tapestry, Pastry, Chord oder CAN.
Abbildung 2 - 6: Strukturierte, dezentralisirte P2P-Architektur
- 15 -
2. Technologischer Hintergrund
•
Unstrukturiert, dezentralisiert: In diesen Systemen gibt es auch keine zentralen
Server (sh. Abb. 2-7). Hinzu kommt, dass die vordefinierte Netzwerkstruktur
wegfällt und es keine Regelung über die Dateiplatzierungen mehr gibt. Dadurch
werden die Suchmechanismen meist über Flooding umgesetzt, so dass eine sehr
hohe Netzlast entsteht. Ein Beispiel für ein unstrukturiert dezentralisiertes Peerto-Peer-Netzwerk ist Freenet.
Abbildung 2 - 7: Reine P2P-Architektur
Zentralisierte Systeme haben zwar den Vorteil, dass Anfragen durch zentrale Indexe
leichter realisiert werden können, jedoch gerade die zentralen Server bilden den
Schwachpunkt dieser Netzwerke. Zum einen können dadurch schnell Engpässe
entstehen, wenn die Anzahl der Anfragen auf einem Server steigt, und zum anderen
funktioniert das Netzwerk ohne die Server nicht. Somit gibt es zentrale
Angriffspunkte, um das gesamte Netzwerk einzuschränken. Ein weiterer Punkt ist die
Vertraulichkeit der Daten. Dritte können leicht von wenigen Stellen aus das gesamte
Netzwerk überwachen.
Dezentralisierte Netzwerke haben diese Probleme nicht. Sie sind sehr viel robuster
gegen Ausfälle und Überwachung, da es keine zentralen Instanzen gibt. Wenn
wenige Knoten ausfallen, bleibt das Netzwerk weiterhin funktionsfähig. In
unstrukturierten Systemen entsteht das Problem des Overheads der Suche.
Im Gegensatz dazu stehen die strukturierten Netzwerke. DHT – Systeme (dt.:
verteilte Hashtabellen) bieten eine Hashtabellen-ähnliche Funktionalität an, bei der
Objekte auf Knoten abgebildet werden. Das System liefert auf die Anfrage nach
einem Objekt den Knoten, der es speichert. [dp]
- 16 -
2. Technologischer Hintergrund
2.5 Peer-To-Peer-Netze für Live Video Streaming
Der folgende Abschnitt besteht zum Großteil aus einer Übersetzung des
englischsprachigen Artikels „A survey on peer-to-peer video streaming systems“ [sr],
welcher die unterschiedlichen P2P Streaming Architekturen analysiert.
In letzter Zeit steigt die Zahl der Benutzer, die Video-over-IP im Internet nutzen. Das
traditionelle Client/Server-Videostreaming kostet die Provider viel Geld wegen der
benötigten Bandbreite. Die P2P Netze sind der beste Anreiz für neue verteilte
Netzwerkanwendungen. Kürzlich wurden von einigen Anbietern P2P Streaming
Systeme eingeführt, die Live- und Video-on-Demand (VoD) Streaming-Dienste
anbieten, deren Kosten deutlich geringer ausfielen. In diesem Kapitel werden die
existierenden P2P Lösungen für Live Video Streaming betrachtet. Die Topologien für
diese P2P Streaming Systeme sind Baum (tree), Multi-Baum (multi-tree) und
vermaschte (mesh) Strukturen. Im Folgenden werden die Herausforderungen und
die Lösungen für die Live Video Streaming Systeme in einer P2P-Umgebung
geschildert.
2.5.1 Einführung
Im Jahr 2006 stieg die Zahl der ausgelieferten Video Streams im Internet um 38,8 %
auf 24,92 Mrd. Allein youtube.com hostet mehr als 45 TBytes Videomaterial und die
Anzahl der angeschauten Videos bis September 2006 stieg auf 1,73 Mrd. Bei
steigenden Bandbreiten im Zugang wird erwartet, dass der Video-Verkehr der
dominierende Datenverkehr in der Zukunft sein wird.
Die Basislösung für Videostreaming ist das Client/Server Model. Der Client initiirt
eine Verbindung mit dem Quellserver und der Videoinhalt wird direkt zum Client
gestreamt. Eine Variation von diesem Model ist die Content Delivery Network (CDN)
-basierte Lösung. Bei ihr werden zuerst die Inhalte zu anderen Zustellservern
geschoben, die an strategischen Stellen im Netz platziert sind, so dass bei einem
Download der Client aufgefordert wird, von dem am nähsten liegenen Server die
Daten zu laden. CDN kürzt sehr effektiv die Zeit zum Download und kann damit mehr
Benutzer gleichzeitig bedienen. Youtube setzt CDN ein, um seine Endnutzer zu
versorgen. Die größte Herausforderung für die Server-basierte Architektur liegt bei
der Skalierbarkeit. Die Videos mit hoher Qualität brauchen auch eine hohe
Datenrate. Mit den heutigen Kompressionsverfahren benötigt man 400 kbps, um TV
Qualität zu erreichen. Die Bandbreite des Providers muss proportional mit der
Clientzahl wachsen. Das macht das Server-basierte Video Streaming teuer und
stimuliert gleichzeitig die Entwicklung von P2P Anwendungen.
Die Grundidee bei den P2P Applikationen ist, dass die Benutzer als Client und
Server fungieren, bekannt als Peer. Im P2P Netzwerk laden die Benutzer nicht nur
Daten herunter, sondern senden diese auch an andere Benutzer im Netz. Die
Uploadgeschwindigkeit von den Endnutzern wird effizient ausgenutzt, um die sonst
reduzierte Bandbreite beim Client/Server Prinzip zu ersetzen. Anwendungen wie
BitTorrent und eMule werden verbreitet angewendet, um schnellen Datenaustausch
über das Internet zu ermöglichen. Weiter wird die P2P Technologie eingesetzt, um
Dienste wie Mediastreaming anzubieten. Anwendungen wie PPLive und PPStream
wurden entwickelt, um Dienste wie Video-on-Demand und Live-TV zu unterstützen.
- 17 -
2. Technologischer Hintergrund
Studien zufolge haben in 2006 mehr als 200.000 Users gleichzeitig broadcast Videos
geschaut, mit einer Bitrate von 400 bis 800 kbps.
Die P2P Streaming Systeme können in zwei Gruppen klassifiziert werden. Das sind
die Baum- und die vermaschten Strukturen. Die Baumstruktur besitzt gut organiserte
Overlaystruktur und liefert Videos, indem sie die Daten an ihren untergeordneten
Knoten (children peers) sendet. Ein grosser Nachteil von dieser Architektur ist ihre
Anfälligkeit für Benutzerdynamik im Netz. Beispielsweise wenn sich ein Benutzer
abmeldet, wird er die Übertragung an seine Kinder stören. Bei den vermaschten
Strukturen sind die Peers nicht an eine statische Topologie gebunden. Stattdessen
ist die Architektur auf das ständige An- und Abmelden von Benutzern spezialisert.
Die Peers verbinden sich dynamisch mit einer Zufallszahl von anderen Peers in dem
System. Periodisch tauschen sie Informationen über ihren Datenbestand aus. Die
Peers beziehen die Videodaten von ihren Nachbarn, die bereits die Daten erhalten
haben. Diese Eigenschaften machen die vermaschten Videostreaming Systeme sehr
robust gegen Benutzerdynamik. Dennoch, die ständige Bewegung von Peers macht
die Effizienz von Videoverteilung unberechenbar. Die Pakete können
unterschiedliche Routen nehmen, um an das Ziel zu kommen. Als Konsequenz
leiden die Benutzer an abfallender Videoqualität durch die niedrigen Bitraten, längere
Startupverzögerungen und Einfrieren des Bildes während der Übertragung.
Das Videostreaming kann man in zwei Kategorien klassifizieren: Live Video und
Video-on-Demand. Bei der Live Übertragung werden die Inhalte in Echtzeit unter
allen Nutzern verbreitet. Das Abspielen des Videos ist unter allen Peers
synchronisiert. Dagegen erfreuen sich die Video-on-Demand Nutzer an der
Flexibilität, sich diejenigen Videos anzuschauen, die sie möchten und wann sie
möchten. Das Abspielen von einem Video ist nicht unter den Peers synchronisiert. In
diesem Abschnitt werden die verschiedenen Overlaystrukturen näher beschrieben.
2.5.2 Baumbasierte Systeme
In den jungen Jahren des Internet wurde das IP Level Multicast als effizienter Weg
zum Streamen von Audio und Video eingesetzt. Bei der IP Mutlicast Session ist der
Server mit allen Clients verbunden, indem sie einen Multicast Baum mit Hilfe der IP
Router aufbauen. Leider ist dieses Verfahren mit einer hohen Komplexität und
Verwaltungsaufwand verbunden. Deswegen fand das IP Level Multicast nie eine
größere Anwendung im Internet. Stattdessen wurden die Funktionen auf der
Anwendungsschicht implementiert. Videoserver und User formen das Application
Layer Multicast, wo die Videoinhalte verbreitet werden.
•
Single-tree Streaming
Ähnlich wie beim IP Multicast Baum, welcher auf Routern auf der Netzwerkschicht
basiert, bilden die User einen Baum auf der Anwendungsschicht, dessen Wurzel
beim Videoserver liegt (sh. Abb. 2-8). Jeder Peer verbindet sich mit dem Baum auf
einer bestimmten Ebene. Er bekommt die Videodaten von seinen Eltern über sich
und leitet die empfangenen Inhalte weiter an seine Kinder. Abbildung 2-8 illustriert
einen Application Layer Multicast Baum mit zehn Knoten.
- 18 -
2. Technologischer Hintergrund
Es gibt zwei Peers auf Schicht 1, die ihre Daten direkt vom Streamingserver
beziehen. Vier Peers auf Schicht 2 bekommen die Pakete von den Eltern von Schicht
1. Drei von denen leiten die erhaltenen Videodaten an vier weitere Peers auf die
unterste Ebene weiter.
Abbildung 2 - 8: P2P Video Streaming auf Basis von Application Layer Multicast
Bei dieser Konstellation aus zehn Peers sind mehrere Möglichkeiten vorhanden, um
einen Streamingbaum aufzubauen. Die Hauptbetrachtung beinhaltet die Tiefe des
Baums und die Auslastung der inneren Knoten. Peers aus den niedrigen Schichten
erhalten den Videostrom vor den Peers aus den höheren Schichten. Um die
Verzögerungen zu minimieren, sollte man die Anzahl der Schichten so klein wie
möglich halten. Mit anderen Worten, die Baumtopologie sollte so breit wie möglich
auf einer Schicht sein. Die innen liegenden Knoten können mit ihrer
Uploadgeschwindigkeit nur an eine begrenzte Zahl von Kinderknoten Daten
weiterleiten. Die Bitrate beschränkt ihre Kapazität. Im Normalfall für die Zwecke von
load balancing und Fehlerstabilität muss die Ausgangsgeschwindigkeit der Peers
unterhalb ihres Maximum liegen.
Ein anderer wichtiger Punkt bei der Baumstruktur ist die Wartung des Systems. Die
Benutzer können im Regelfall sehr dynamisch sein. Der User kann eine Session
angekündigt oder unangekündigt, etwa beim Rechner-Absturz, verlassen. Beim
Verlassen wird die Verbindung zu allen seinen Kinderknoten unterbrochen und damit
können sie keine Videosequenzen mehr empfangen. Abbildung 2-9 zeigt ein
mögliches Szenario, wenn ein Peer nahe an dem Videoserver den Baum verlässt. So
werden alle fünf der unterliegenden Knoten vom Quellserver getrennt.
- 19 -
2. Technologischer Hintergrund
Abbildung 2 - 9: Ausfall eines Knoten
Abbildung 2-10 zeigt wie der Baum die Verbindung zu den Peers erneut herstellt,
indem sie vom Server oder anderen Peers vererbt wird.
Abbildung 2 - 10: Korrektur des Baumes nach dem Ausfall
Die Baumstruktur kann entweder zentral oder verteilt aufgebaut und gewartet
werden. Bei der zentralisierten Lösung kontrolliert der Server den Aufbau und die
Wiederherstellung eines Baums. Wenn sich ein User im System anmeldet,
kontaktiert er als erstes den Zentralserver. In diesem Fall entscheidet der Server auf
Basis der momentanen Baumstruktur, an welcher Position sich der Peer verbindet
und benachrichtigt seine Elternknoten. Der Server kann das Verlassen eines
Knotens aufspüren, indem er seine Abmelde-Nachricht auswertet oder nach einem
bestimmten Timeout-Verfahren. In beiden Fällen muss die Topologie des Systems
neu kalkuliert werden. Bei großen Streaming Systemen kann es vorkommen, dass
die Serverressourcen knapp werden. Um dies zu vermeiden, werden Algorithmen
angewendet, um die nötigen Wartungsarbeiten verteilt zu erledigen.
- 20 -
2. Technologischer Hintergrund
Ein weiterer Nachteil der Ein-Baum-Strukturen ist, dass alle Knoten, die ein Blatt im
Baum sind, also am Rande der Struktur sind, nicht mit ihrer Uploadgeschwindigkeit
beitragen, sondern nur Daten bekommen. Bei größeren Systemen wird dadurch die
Effizienz des Gesamtsystems erheblich beeinträchtigt.
•
Multi-tree streaming
Bei den Multi-Baum Strukturen teilt der Server den Stream in mehrere Unterstreams
(sub-stream) auf. Statt nur einen Baum zu benutzen, wird jeweils einen für jeden
Sub-Stream eingesetzt. Jeder Peer meldet sich an jedem Baum an, um Daten von
jedem Unterstream zu empfangen. Der Datenstrom von jedem Sub-Stream fließt
Schicht für Schicht vom Server bis zu den Blättern. Ein Peer liegt an verschiedenen
Stellen in jedem Baum. Beispielsweise kann er ein innerer Knoten in einem Baum
sein und in dem Anderen ein Blatt sein. So wird immer die Uploadgeschwindigkeit
von jedem Peer ausgenutzt, immer dann wenn er ein interner Knoten in einem Baum
ist. Dies lässt sich auch verbessern, indem die Anzahl der Bäume, wo der Peer als
interner Knoten fungiert, proportional zu seiner Uploadbitrate ist. In so einer MultiBaum Struktur mit m Sub-Streams ist jeder einzelne User ein innerer Peer in nur
einem Baum und ein Blatt in den restlichen m-1 Unterbäumen. Abbildung 2-11 zeigt
ein Beispiel mit 7 Peers und 2 Sub-Streams. Der Server splittet den Video in zwei
Teile auf und verteilt die Daten entsprechend in den linken und in den rechten SubStream. Peer 0, 1 und 2 sind innere Knoten in dem linken Unterbaum und Blätter in
dem rechten. Gleichartig sind auch Peers 3, 4 und 5 auf der anderen Hälfte
aufgeteilt.
Abbildung 2 - 11: Multi-tree basiertes Streaming mit zwei Sub-streams
Jeder Benutzer besitzt eine Bandbreite von 1 und kann damit gleichzeitig an zwei
seiner Kinder mit einer Bitrate von 0,5 Daten hoch laden. Hier ist zu merken, dass
Peer 6 in beiden Sub-Bäumen ein Blatt ist. Dies ist deswegen der Fall, weil nur sechs
Peers nötig sind, um an sieben Clients zu streamen.
- 21 -
2. Technologischer Hintergrund
2.5.3 Vermaschte Systeme
Wie bereits beschrieben, bei den Baum-basierten Strukturen hat ein Peer nur einen
Elternknoten, von welchem er alle Inhalte herunterlädt. Dieses Design ist anfällig bei
Benutzerdynamik. Verlässt ein Elternknoten das Netz, so bleibt seine Nachkommen
unversorgt. Mit steigender Häufigkeit dieser An- und Abmeldevorgänge wird die
Wartung des Systems zu einer großen Herausforderung. Dafür steigt in letzter Zeit
auch die Zahl der vermaschten Strukturen. Bei denen gibt es keine statische
Streamingtopologie. Die Peers bauen und trennen ihre Verbindungen sehr
dynamisch. Sie verwalten eine Großzahl von Verbindungen zu anderen Peers im
Netz. Ein Peer kann gleichzeitig mit mehreren anderen Peers Daten herunter- und
hochladen. Wenn ein Nachbar das Netz verlässt, kann der User die Daten von den
übrig gebliebenen weiter empfangen. Gleichzeitig sucht er nach anderen Peers, mit
welchen er eine neue Verbindung initiieren kann, um eine Mindestzahl von
Verbindungen aufrecht zu erhalten. Dies macht die vermaschten Strukturen sehr
robust gegen Peerdynamik. In diesem Abschnitt wird ein tieferer Blick ins System
verschafft.
Ähnlich wie bei den P2P File Sharing Systemen (BitTorrent) besitzen die
vermaschten Systeme einen Tracker, welcher eine Liste von aktiven Peers in der
Videosession verwaltet. Wenn sich ein neuer Peer anmeldet, kontaktiert er als erstes
den Tracker und teilt ihm Informationen wie IP Adresse und Portnummer mit. Der
Tracker antwortet ihm mit einer Liste, die eine Menge von zufälligen anderen Peers
beinhaltet. Die Anzahl kann sehr variieren, von einigen Wenigen bis zu Hunderten.
Nach dem Erhalten der Initialliste versucht der neue Peer sich mit Einigen zu
verbinden. Wenn eine neue Verbindung entsteht, dann fügt der User die
Remoteadresse zu seiner Nachbarliste. Nachdem er genug Nachbarn gefunden hat,
beginnt er mit dem Austausch von Videosequenzen. Abbildung 2-12 zeigt den
Initialprozess.
Um seine Liste aktuell zu halten, updatet der Peer sie ständig während der Session.
Er kann auch beim Tracker nach einer aktuellen Liste nachfragen, oder mit anderen
Peers sich die eigenen austauschen. Wenn ein Peer das Netz angekündigt verlässt,
dann meldet er sein Verlassen beim Tracker und bei den anderen Peers, damit sie
ihn aus der Liste streichen können. Um unangekündiges Verlassen zu erfassen,
senden die Knoten unter sich keep-alive Nachrichten. So werden Peers aus der Liste
entfernt, wenn sie nach einer Timeout-Zeitperiode keine Nachricht verschickt haben.
- 22 -
2. Technologischer Hintergrund
Abbildung 2 - 12: Abfrage der Peerliste vom Tracker-Server
Jedes System implementiert eigene Algorithmen, mit wem die Peers eine Verbindung
aufbauen. Diese Entscheidung wird von verschiedenen Kriterien beeinflusst, wie:
•
Auslastung und Ressourcenverfügbarkeit auf beiden Seiten, z.B. Anzahl der
Verbindungen, Upload- und Downloadgeschwindigkeit, CPU- und
Speicherauslastung.
•
Qualität einer potenziellen Verbindung, z.B. die Verzögerung und Verlustrate
zwischen beiden Enden.
•
Gesuchte Inhalten, z.B. ob der User die Videoinhalten braucht, die ihm der
Lokaluser anbieten könnte.
Mit Hilfe dieser Kriterien wird eine bessere Streamingperformanz erreicht.
Bei der Baumstruktur fließt der Datenstrom von der Videoquelle zu den Peers
entlang des Baumes. Bei den vermaschten Topologien findet dieses Verfahren
keinen Einsatz. Hier schneidet der Quellserver die Videoinhalte in viele kleine
Stücke, die Videochunk heißen. Sie sind die Grundeinheiten und beinhalten
Mediadaten für ein sehr kleines Zeitintervall, z.B. 0,1 Sekunden. Jedes Chunk hat
eine eindeutige Sequenznummer, die an den Videoinhalt angepasst ist. Die Peers
verbreiten die Chunks durch das Netz. So können sie verschiedene Wege nehmen,
bis sie beim Benutzer angekommen sind. Meistens kommen sie in vermischter
Reihenfolge an und deswegen müssen sie zuerst gepuffert werden, bis die
restlichen Chunks erhalten sind. Dann können sie zum Abspielen gestellt werden.
Die gepufferten Chunks werden weiter an den Nachbarn geschickt. Je nach
Systemdesign können manche Peers die Chunks einige Minuten puffern. Beim
Livestreaming steigt die Sequenznummer der gepufferten Chunks mit dem
Playbackfortschritt konstant.
- 23 -
2. Technologischer Hintergrund
Es gibt zwei Arten von Datenaustausch bei den vermaschten Systemen: push und
pull. Beim push-Modell schicken die Peers ihre Daten blind zu ihren Nachbarn. Da
keine klare Eltern/Kinder Beziehung existiert, kann es vorkommen, dass zwei Peers
das gleiche Chunk an einen Peer schicken. So wird die Uploadgeschwindigkeit mit
unnötiger Redundanz belastet. Um dieses Problem zu umgehen, muss das
Verschicken von Chunks unter den Nachbarn sorgfältig geplant werden. Dieses
Verfahren muss auch beim Eintreffen oder Verlassen von Peers funktionieren.
Ein anderer Weg, dieses Problem zu vermeiden, ist die pull-Methode. Die Daten
werden „gezogen“ statt blind „gedrückt“. Die Peers tauschen die sog. buffer maps,
die die Sequenznummern der verfügbaren Chunks beinhalten. Nachdem ein User
die Buffer Maps von seinen Nachbarn erhalten hat, kann er entscheiden, welche
Chunks von welchem Peer er braucht. Er sendet eine Anfrage an den
entsprechenden Nachbarn und bekommt den richtigen Chunk. Damit wird die
Redundanz von Chunks vermieden. Der häufige Austausch von Buffer Maps und die
häufigen Chunk-Anfragen sind mit mehr Signalisierungsoverhead verbunden und
können das Videostreaming zusätzlich verlangsamen.
2.6 OSGi - Dynamic Module System for Java
2.6.1 Einführung
Das Konzept der Modularisierung ist heute als Mittel zur Kompläxitätsreduzierung bei
der Entwicklung großer Anwendungssysteme unumstritten. In Java gestaltet sich die
Umsetzung dieses Konzepts schwierig, da unterstützte Sprachkonzepte fehlen.
Monolithische Anwendungssysteme sind die häufige Folge. [Osp]
2.6.2 Die OSGi Service Plattform
Die OSGi Service Plattform löst dieses Problem, indem sie ein dynamisches
Modulsystem bereitstellt. Es handelt sich um eine javabasierte Softwareplattform, die
die dynamische Integration und das Fernmanagement von Softwarekomponenten
(Bundles) und Diensten (Services) ermöglicht. Bundles und Services können zur
Laufzeit in der Serviceplattform installiert und gestartet, gestoppt und deinstalliert
werden, ohne dass die Plattform als Ganzes angehalten werden muss. [Osp]
Die OSGi Service Platform wird von der OSGi Alliance vorangetrieben. Gegründet
wurde die OSGi Alliance 1999. Ihr gehören (Stand März 2008) 30 Firmen aus recht
unterschiedlichen Branchen als Full Member (Vollmitglied) an, wie etwa Sun
Microsystems, IBM, Nokia, Motorola, Oracle, NEC, Hitachi, Sprint, Samsung,
Siemens, Telefónica, BEA, Deutsche Telekom, Red Hat und ProSyst. Zu den
Vollmitgliedern kommen (Stand März 2008) noch 9 sogenannte Adopters hinzu,
darunter auch die Eclipse Foundation, sowie 14 Supporters, darunter z. B. LG
Electronics. Es existieren Expert Groups für die Bereiche Residential, Enterprise,
Mobile, Vehicle und Core Platform. [Owk]
Durch die Standardisierung wurde die OSGi Service Plattform für den Einsatz in
verschiedenen Bereichen interessant:
- 24 -
2. Technologischer Hintergrund
•
Smart Phones: Durch den JSR 232.
•
Automotive: BMW setzt als Grundlage der Telematiksysteme ihrer künftigen
Fahrzeuge auf die OSGi Service Plattform
•
Desktop-Applikation: Seit der Version 3.0 setzt Eclipse grundlegend auf
OSGi.
•
Serverseitige Anwendungen: Ab Version 6.1 basiert der WebsphereApplikationserver auf der OSGi Service Plattform.
2.6.3 Implementierungen
Es existieren folgende Implementationen von OSGi:
•
Eclipse Equinox: Eclipse Equonix ist die Basis aller Eclipse-Anwendungen,
vor allem die Eclipse-DIE. Damit ist Equinox wohl die am weitesten verbreitete
laufende OSGi Plattform auf dem Desktop
•
Prosyst mBedded Server Equinox Edition: Die mBedded Server Equinox
Edition wird von der Firma Prosyst entwickelt. Seit März 2007 ist sie auch als
Open-Source Produkt verfügbar.
•
Knopflerfish: Knopflerfish ist die Open-Source-Variante der kommerziellen
OSGi-Implementierung Knopflerfish Pro. Die OSGi-R4-Implementation heißt
Knopflerfish 2 und steht unter eigener Lizenz, die sich an der BSD-Lizenz
orientiert.
•
Apache Felix: Felix [af] ist seit Anfang 2007 ein Top-Level-Projekt bei
Apache. Felix basiert auf einer OSGi-Implementierung namens Oscar [os].
Felix steht unter der Apache Lizenz 2.0.
2.6.4 Das OSGi Framework
Die Basiskomponente der Plattform ist das OSGi Framework, das einen Container
für Bundles und Services zur Verfügung stellt. Die Abbildung 2-13 zeigt den
Schichtenaufbau einer typischen OSGi-Architektur.
- 25 -
2. Technologischer Hintergrund
Abbildung 2 - 13: OSGi Systemschichtung
[Quelle:WiKipedia]
2.6.5 Grundelemente
Bundles:
Ein Bundle ist eine fachlich oder technisch zusammenhängende Einheit von Klassen
und Ressourcen, die eigenständig im Framework installiert bzw. deinstalliert werden
kann. Die in einem Bundle enthaltenen Klassen und Ressourcen sind zunächst für
andere Bundles nicht sichtbar. Um sie für andere Bundles nutzbar zu machen, muss
ein Bundle die Packages, in denen die Klassen und Ressourcen enthalten sind,
explizit exportieren. Dazu müssen die Packages, die ein Bundle benutzen möchte,
von ihm importiert werden. Das Im- und Exportieren von Packages erfolgt über eine
Manifest-Datei. Das OSGi Framework sorgt zur Laufzeit dafür, dass jedem Bundle
die importierten Java-Packages bereitgestellt werden. Ist dies nicht möglich, weil
etwa die benötigten Ressourcen nicht vorhanden sind, kann das Bundle im
Framework nicht zur Ausführung gebracht werden. [Osp]
Services:
Als weiteres Mittel zur Entkopplung zwischen unterschiedlichen Modulen können
Bundles Services verwenden, die systemweit zur Verfügung stehen. Ein Service ist
ein Java-Objekt, das unter einem Interface-Namen bekannt gemacht wird. Die
Registrierung eines Service erfolgt über die Service Registry, die zentral und
bundleübergreifend bereitsteht und an der die angemeldeten Dienste von beliebigen
- 26 -
2. Technologischer Hintergrund
Bundles abgefragt werden können. Bundles, die einen bestimmten Dienst benötigen,
können den entsprechenden Service dann von der Service Registry abfragen, ohne
konkret wissen zu müssen, welche Implementierung dahintersteht. [Osp]
Management Agents:
Über einen Management Agent, der Bestandteil des jeweiligen Frameworks ist,
können Bundles verwaltet werden (Installieren, Deinstallieren, Starten, Stoppen).
Der Agent liegt gewöhnlich selbst in Form eines oder mehrerer Bundles vor. Im
einfachsten Fall stellt ein Management Agent eine textbasierte Konsole bereit, über
die Bundles mittels Kommandos verwaltet werden können. [Osp]
- 27 -
3. Konzept
3. Konzept
Im vorigen Kapitel wurden einige Internetprotokolle erläutert, die für die
Multimediakommunikation im Internet zuständig sind. Anschließend wurden die P2PNetze vorgestellt, mit deren Hilfe man den Datenaustausch ermöglicht.
In diesem Kapitel wird weiter auf den bisher vorgestellten Technologien aufgebaut.
Es wird das Konzept vorgestellt, um während einer Audio- bzw. Videokonferenz Live
Video zu streamen. Dafür muss man zuerst eine Konferenz aufbauen können. Ist es
dann soweit, können sich die Teilnehmer in einem Peer-to-Peer Netz anmelden, um
die gewünschten Videos auszutauschen.
Wichtig für das Endergebnis ist, dass ein Weg gefunden wird, wie zwischen zwei
Protokollen umgeschaltet werden kann. In diesem Fall bedeutet dies eine erneute
Signalisierung für die beteiligten User Agents, um ihnen mitzuteilen, dass ein per
P2P live gestreamter Video zur Session hinzugefügt wird.
3.1 SIP-basierte Konferenz mit Live Video Streaming
SIP ist ein Protokoll zum Einleiten, Manipulieren und Beenden von Multimedia über
IP-Sessions. Gemäß RFC3261 kann eine derartige Session auch eine Konferenz
zwischen drei oder mehr Teilnehmern darstellen. Es existieren verschiedene
Ansätze für das Aufbauen einer Konferenz. Eine Möglichkeit bietet sich mit Hilfe
einer MCU (Multipoint Control Unit), auch als Conference Server bekannt. Er besteht
aus zwei Teilen – Focus und Mixer. Im Falle einer SIP-basierten Sprach- bzw.
Multimediakonferenz benötigt man ein Element, das für jedes an einer Konferenz
beteiligte Endsystem jeweils die Rolle einer SIP-Kontaktinstanz übernimmt. Diese
Rolle übernimmt der Focus. Des Weiteren müssen die von allen beteiligten User
Agents abgehenden Nutzdaten (Audio/Video) zu einem Gesamtsignal gemischt und
diesem wiederum allen beteiligten User Agents als ankommendes Nutzdatensignal
zur Verfügung gestellt werden. Für diese Aufgabe wird den Mixer benötigt, welcher
durch den Focus anhand der per SIP/SDP ausgetauschten Session- und MedienEigenschaften gesteuert wird. [sip]
Es gibt auch die so genannten Ad-hoc Konferenzen, wo jeder User Agent eine
Konferenz starten kann und andere Agents einlädt. Dieser Benutzer wird Focus User
Agent genannt. In Abbildung 3-1 wird kurz dargestellt, wie der Verbindungsaufbau
aussieht.
- 28 -
3. Konzept
Abbildung 3 - 1: Aufbau einer Ad-hoc Konferenz
Der Focus User Agent versendet seine INVITE – Nachricht, in welcher der „isfocus“ Parameter gesetzt ist. Dieser Parameter besagt, dass der Absender eine Konferenz
initiieren möchte. Weitere Informationen findet man in RFC4579 [r3].
Nachdem der Initiator die INVITE - Nachrichten an jeden verschickt hat, der an der
Konferenz teilnehmen möchte, wartet er auf die entsprechenden Antworten.
F1:
INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP l00.100.100.101:5060;branch=z9hG4bKfw19b
Max-Forwards: 70
To: Alice <sip:[email protected]>
From: Bob <sip:[email protected]>;tag=76341
Call-ID: [email protected]
CSeq: 1 INVITE
Contact: "Bob"
<sip:100.100.100.101:5060;transport=udp>;isfocus
Content-Type: application/sdp
Content-Length: 158
v=0
o=bob 2890844526 2890844526 IN IP4 100.100.100.101
s=Phone Call
c=IN IP4 100.100.100.101
t=0 0
m=audio 49170 RTP/AVP 0
a=rtpmap:0 PCMU/8000
- 29 -
3. Konzept
Die eingeladenen User Agents analysieren die INVITE und wenn sie diese Art von
Konferenz unterstützen, antworten sie mit dem Header-Argument Supported:conf.
F2:
SIP/2.0 200 OK
Via: SIP/2.0/UDP l00.100.100.102:5060;branch=z9hG4bKfw19b
To: Bob <sip:[email protected]>;tag=a53e42
From: Alice <sip:[email protected]>;tag=76341
Call-ID: [email protected]
CSeq: 1 INVITE
Contact: "Alice" <sip:[email protected]>
Supported:conf
Content-Type: application/sdp
Content-Length: 155
v=0
o=Alice 2890844528 2890844528 IN IP4 l00.100.100.102
s=Phone Call
c=IN IP4 l00.100.100.102
t=0 0
m=audio 60000 RTP/AVP 0
a=rtpmap:0 PCMU/8000
Das SIP Protokoll sieht vor, dass während einer bereits laufenden Kommunikation
Änderungen vorgenommen werden können. Das Senden einer INVITE-Anfrage im
Rahmen einer bereits bestehenden SIP-Session wird als re-INVITE bezeichnet.
Üblicherweise dient das zur Modifizierung der Session, die sich auf den
Nutzdatenaustausch zwischen den Endsystemen auswirkt.
In dieser Anwendung wird sich genau diese Eigenschaft zu Nutze gemacht. Damit
alle User Agents mitbekommen, dass Einer ein Video streamen möchte, verschickt er
an Alle einen erneuten INVITE (re-INVITE), um die anderen Teilnehmer einzuladen.
Wichtig ist es anzumerken, dass der SIP Header sich nicht verändert, und das CallID Feld muss sogar gleich bleiben, sonst wird das als ein separater
Verbindungsaufbau erkannt.
Das Neue ist das SDP-Teil. Dort werden alle relevanten Informationen übergeben,
die die anderen User Agents benötigen, um sich zum Teil von dem Videostreaming
zu machen.
- 30 -
3. Konzept
INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP l00.100.100.101:5060;branch=z9hG4bKfw19b
Max-Forwards: 70
To: Alice <sip:[email protected]>
From: Bob <sip:[email protected]>;tag=76341
Call-ID: [email protected]
CSeq: 1 INVITE
Contact: "Bob"
<sip:100.100.100.101:5060;transport=udp>;isfocus
Content-Type: application/sdp
Content-Length: 266 (z.B.)
v=0
o=bob 2890844526 2890844526 IN IP4 100.100.100.101
s=Streaming Session
i=A Streaming session declared within the session
description protocol
c=IN IP4 100.100.100.101
t=0 0
m=application 7200 TCP/STS 515
a=connection:new
a=control: sts://l00.100.100.101
a=fmtp:515 bootstrap: uri="sts://l00.100.100.101:7200"
Das m-Feld im SDP Header ist wie folgt definiert:
m=<media> <port> <transport> <format-list>
Es liefert Informationen über den Typ der Media Session, z.B.:
m=application 7200 TCP/STS 515
Hier wird die Bezeichnung TCP/STS (für Striped Session) verwendet, was frei für
unsere Zwecke erfunden ist. Sie wird verwendet, um die externe Anwendung zu
kennzeichnen, die gestartet werden soll.
Betrachten wir:
a=connection:new
a=control: sts:/100.100.100.101
a=fmtp:515 bootstrap: uri="sts:/100.100.100.101:7200"
Das a-Feld beinhaltet die benötigten Attribute für die externe Anwendung. Sie
beschreiben den Verbindungstyp, die Bootstrap IP und Port. Das Feld
connection:new ist ein optionales Feld, welches meint, dass es möglich wäre, mehr
als nur eine Verbindung von diesem User Agent zu haben. Dieser Fall wird aber nicht
weiter behandelt. Mit control wird die IP Adresse des einladenden Peers mitgeteilt.
Anschließend übergibt das fmtp-Feld die IP Adresse und Portnummer, die zum
Einloggen benötigt werden. Die IP Adresse kommt doppelt vor, da es möglich wäre,
dass die beiden abweichen.
- 31 -
3. Konzept
Als Antwort auf diese Einladung senden die anderen User Agents die
entsprechenden Nachrichten wie folgt:
SIP/2.0 200 OK
Via: SIP/2.0/UDP l00.100.100.102:5060;branch=z9hG4bKfw19b
To: Bob <sip:[email protected]>;tag=a53e42
From: Alice <sip:[email protected]>;tag=76341
Call-ID: [email protected]
CSeq: 1 INVITE
Contact: "Alice" <sip:[email protected]>
supported:conf
Content-Type: application/sdp
Content-Length: 155
v=0
o=Alice 2890844528 2890844528 IN IP4 l00.100.100.102
s=Phone Call
c=IN IP4 l00.100.100.102
t=0 0
m=application 7878 TCP/STS 515
a=fmtp:515 status=starting
Die Nachricht sieht wie eine typische OK-Meldung aus,
nur werden zwei
Zusatzfelder mit versendet, die besagen, dass sich der eingeladene Peer in einer
Boot-Phase befindet.
Nachdem das Aufbauen einer Konferenz beschrieben wurde, wird ein tieferer Blick in
die P2P Netze benötigt. Es wird die Pastry-Infrastruktur und das damit verbundene
Konzept vorgestellt.
3.2 Das P2P Konzept
In P2P-Architekturen ohne zentralen Verwaltungsserver besteht die Notwendigkeit
zur Selbstorganisation und der dezentralen Datenhaltung. Es wird dazu eine Art
Datenbank benötigt, die alle angemeldeten Clients, deren Ressourcen und die Route
dahin kennt. [thr] Alle Implementierungen von DHT basieren auf Hashtabellen, die
ihrerseits auf Hashfunktionen basieren. Die bekanntesten Hashalgorithmen sind
SHA-1 und MD5, wobei sich SHA-1 in der P2P-Welt durchgesetzt hat.
3.2.1 Hashfunktionen
Hash-Funktionen reduzieren Daten beliebiger Länge auf eine numerische Ausgabe
mit fester Länge. Da die Quellmenge in den meisten Fällen größer als der
Ergebniswertebereich ist, kann es vorkommen, dass mehrere Eingangswerte
dasselbe Ergebnis erzeugen. Solche Fälle werden als Kollisionen bezeichnet. [thr]
- 32 -
3. Konzept
Der Hashwert zu einer Nachricht muss relativ schnell und einfach zu berechnen sein,
jedoch die Umkehrung, also der Rückschluss von einem gegebenen Hashwert auf
die dazugehörige Nachricht darf nur sehr schwer möglich sein. Man spricht deshalb
auch von Einweg – Hashfunktionen.
Das SHA-Verfahren wurde vom National Institute of Standards and Technology
(NIST) in Zusammenarbeit mit der National Security Agency (NSA) 1994 als
Nachfolger von MD5 entworfen. Es erzeugt Hash-Werte mit der Länge von 160 Bit.
Wegen eines Designfehlers wurde 1995 der Algorithmus durch einen weiteren LinksShift erweitert und zu SHA-1 umbenannt.
Beim SHA-1 werden die Eingangsdaten in 512-Bit Blöcke eingelesen, die man auf
fünf 32-Bit-Wörter in den 160 Bits breiten Puffer verteilt. Es werden vier Runden pro
Datum mit 20 Operationen pro Runde absolviert. [thr]
Abbildung 3 - 2: Blockschaltbild MD5
(Quelle:Wikipedia)
Um alle Hashwerte zu speichern, werden bei der DHT die so genannten HashTabellen gebildet. Eine Hash-Tabelle speichert zu einem beliebigen Schlüssel den
dazu gehörigen Wert ab. Die Tabelle ist hierzu in zwei Spalten aufgeteilt, eine Spalte
speichert den für die Adressierung der Spalte notwendigen Schlüssel ab, die andere
speichert einen beliebigen dazu gehörigen Wert. Zusätzlich wird zu jedem Schlüssel
der dazu gehörige Hash-Wert zur schnellen Identifizierung abgelegt (Indexierung).
[thr]
Hash-Tabellen implementieren immer die drei wesentlichen Funktionen:
•
Ablegen eines Schlüssel-Wert-Paars; eventuell bereits abgelegte Werte
werden überschrieben.
•
Löschen einer Tabellenzeile anhand des Schlüssels.
•
Abfragen eines Wertes mit einem Schlüssel.
- 33 -
3. Konzept
Eine Suchanfrage mit einem Suchschlüssel kann sehr schnell ausgeführt werden, da
mit Hilfe der Hashfunktion sich die Indexposition der richtigen Zeile ermitteln lässt.
Allerdings funktioniert die Suche nur einseitig schnell. Soll anhand eines Wertes der
dazugehörige Schlüssel ermittelt werden, müssen alle Werte der Tabelle bis zur
Übereinstimmung auf Gleichheit mit dem Suchschlüssel überprüft werden.
3.2.2 Pastry
Wenn man ein reines Peer-to-Peer Protokoll entwickelt, hat man mit vielen
Designproblemen zu kämpfen. Einige der wichtigsten Designziele sind:
•
Dezentralisierung
Etwas ältere Systeme wie Napster verwenden für die Suchanfragen spezielle
Knoten. Das verspricht keine richtige Lastverteilung im Netz. Natürlich ist mit einer
verteilten Suche ein hoher Kommunikationsaufwand verbunden.
•
Skalierbarkeit
Diesen erhöhten Kommunikationsaufwand versucht das Protokoll Gnutella durch
eine verteilte Suche nach dem Schneeballprinzip (der Vervielfältigung von
Nachrichten) zu lösen. Dies ist eine effektive, aber keine effiziente Lösung. Es kommt
zu einer starken Belastung der unter dem Netzwerk liegenden Infrastruktur, die mit
der Zahl der Knoten wächst. Um dies zu verhindern, ist es notwendig, Nachrichten
möglichst direkt an den zuständigen Knoten zu schicken. [pt]
Idealerweise bringt man ins Netzwerk eine Struktur, die ein schnelles Auffinden des
gesuchten Knotens möglich macht. Ein effizientes Routing-Protkoll soll helfen, dass
der Absender nicht die Struktur des ganzen Netzes kennen muss, sondern dass er
nur das nächste Ziel lokal bestimmen muss.
•
Selbstorganisation
Gegen eine total erfasste Struktur spricht, dass das dynamische Weg- und
Hinzunehmen von Knoten erschwert würde, da alle Knoten von Ausfällen in Kenntnis
gesetzt werden müssten. Genau das ist es aber, was das System effizient leisten
und organisieren soll, das eigene Wachsen und Schrumpfen. [pt]
Pastry versucht die oben genannten Designziele zu verwirklichen. Pastry ist eine
dezentralisierte key-basierte Routing-Infrastruktur für Peer-to-Peer Anwendungen.
Sie ist von der Protokollfamilie der DHTs. Es bietet auf Applikationsschicht einen
skalierbaren und verteilten Objekt-Lokations- und Objekt-Routing-Dienst in einem
potentiell sehr großen Netzwerk. Einzelnen Knoten wird dafür eine
Verarbeitungsschicht samt API angeboten, die es ermöglichen soll, eine Vielzahl von
Peer-to-Peer Applikationen zu verwirklichen (z.B. verteilte Datei- oder
Gruppenkommunikationssysteme). [pt]
Pastry findet Einsatz in verschiedenen Applikationen, darunter Web Caching
(Squirrel), archival file storage (PAST), application-level multicast (Scribe) und
video/content streaming (SplitStream). Die Pastry-DHT wird in einem
Gemeinschaftsprojekt von Microsoft Research, der Rice University, der Purdue
- 34 -
3. Konzept
University und der University of Washington gepflegt. Sie kann sowohl das 128 Bit
MD5-Hash-Verfahren als auch das 160 Bit SHA-1 Verfahren anwenden.
Jeder Knoten in der DHT besitzt eine NodeId, meist 128 Bit und hält 3 Tabellen zum
Routing bereit - Leaf, Neighborhood set und die Routing Tabelle (sh. Abb. 3-3).
Abbildung 3 - 3: Pastry Tabellen
Fordert man effizientes Routing zwischen den Knoten eines vermaschten Netzes
kommt man schnell auf die Idee eine binärbaumartige Struktur zu realisieren. Diese
ermöglicht theoretisch logarithmischen Aufwand bei der Übermittlung von
Nachrichten. Bei einer Schlüssellänge von 128 Bit würden im herkömmlichen
Binärbaum aber 128 Hops notwendig, um zu einem Blatt zu gelangen, was keine
gute Performanz verspricht. Pastry erhöht deshalb die Anzahl der Unterknoten auf
2^b (b standardmäßig 4), wodurch der Baum abflacht und im ungünstigsten Fall 32
Hops notwendig sind. Ein Pastry Node kennt also maximal 2^b direkte
Nachbarknoten, die entsprechend den Ebenen eines Baumes ein gemeinsames
Präfix besitzen.
Abbildung 3 - 4: Pastry, Routingtabelle
- 35 -
3. Konzept
Die Abbildung 3-4 zeigt die Routingtabelle eines Pastry Nodes mit nodeID = 65a1x,
b=4.
Abbildung 3 - 5: Routing einer Nachricht
In Abbildung 3-5 sieht man die prinzipielle Vorgehensweise beim Routen einer
Nachricht zu dem Knoten mit NodeID d46a1c.
Die Routing-Strategien werden jedoch von einem Overlay-Netzwerk, das auf der
DHT aufbaut, verarbeitet. Die Besonderheit von Pastry besteht darin, dass ein
externes Programm zur Bestimmung der Distanz (und somit auch der RoutingStrategie) zwischen den P2PClients aufgerufen werden kann, so kann z. B. eine
Optimierung nach Router- Hop-Counts, Verbindungslaufzeiten, Netzwerkbandbreite
oder Kombinationen verschiedener Verfahren erfolgen.
Pastry bietet auch ein Application Programming Interface (API), welches eine
überschaubare Anzahl an Befehlen besitzt, um die komplette Kommunikation
innerhalb des Netzwerkes zu initialisieren und abzuwickeln:
•
nodeID = pastryInit(Credentials, Application)
Der Aufruf der Funktion pastryInit startet den lokalen Knoten und registriert ihn im
Netzwerk. Er liefert die lokale Knoten-ID zurück und verlangt beim Aufruf sowohl eine
applikationsabhängige Struktur als auch ein Application-Handle, um Rückmeldungen
weiterleiten zu können.
•
route(msg,key)
Die Funktion route veranlasst Pastry die übergebene Nachricht an den Knoten mit
der ebenfalls übergebenen Knoten ID zu übermitteln.
Applikationen, die Pastry verwenden, müssen ihrerseits die folgenden Methoden
exportieren:
- 36 -
3. Konzept
•
deliver(msg, key)
Die Methode deliver wird von Pastry aufgerufen, falls der lokale Knoten der
numerisch naheste zu key ist. Übergeben wird dann die Nachricht msg.
•
forward(msg, key, nextId)
Wird eine Nachricht empfangen, die eigentlich zur Weiterleitung gedacht ist, trifft sie
per forward ein. Sie kann modifiziert oder durch Setzen von msg auf NULL terminiert
werden.
•
newLeafs(leafSet)
Die Methode newLeafs wird von Pastry immer dann aufgerufen. wenn sich
Änderungen im lokalen Leaf-Set ergeben.
Derzeit existiert sowohl eine freie Pastry Implementation der Rice University als auch
ein Paket, das von Microsoft Research zur Verfügung gestellt wird. FreePastry [fp] ist
eine OpenSource Implementation von Pastry und wird in Java entwickelt. Sie bietet
ein objektorientiertes Framework für die Erstellung von P2P-Anwendungen.
Im Folgenden werden zwei Anwendungen vorgestellt, die auf Pastry basieren und für
die spätere Aufgabe eine Rolle spielen werden.
3.2.3 Scribe
Scribe ist ein System, das für Kommunikations- und Nachrichtendienste für beliebig
große Gruppen entwickelt wurde. Es nutzt Multicast auf Anwendungsebene, um
Daten in themenbasierten Gruppen zu verteilen. Scribe ist effizient, flexibel, und
unterstützt auch sehr dynamische Gruppen, mit vielen beitretenden und
verlassenden Mitgliedern. Zudem skaliert es sehr gut. Dies liegt daran, dass Scribe
auf Pastry aufsetzt.
In Pastry bekommt jedes Mitglied eine zufällige ID zugewiesen, welche z.B. durch
kryptografische Hashwert-Berechnung des Öffentlichen Schlüssels eines Mitglieds
ermittelt werden kann. In Pastry können nun Daten von einem Mitglied zu jedem
beliebigen anderen Mitglied versendet werden, wenn dessen ID bekannt ist. Die IDs
sind jeweils kurze Sequenzen von Ziffern der Länge 2b, wobei b eine kleine
Konstante, meist zwischen 2 und 6, ist. Jedes Mitglied im Pastry-Overlay hat eine
Routing-Tabelle, eine Menge von Nachbarn sowie eine Menge von Blättern. Die
Routing-Tabelle eines Mitglieds h enthält Informationen über eine Menge von
Mitgliedern, die ein gewisses Präfix mit h gemeinsam haben. In Reihe i teilen sich die
ersten i−1 Ziffern ihre ID mit Mitglied h. In der Routing-Tabelle gibt es 2b Reihen mit
je 2b Einträgen. Wenn ein Mitglied keine anderen Mitglieder mit passendem Präfix
bestimmter Länge kennt, so ist die entsprechende Reihe in der Routing-Tabelle leer.
Die Menge der Nachbarn eines Mitglieds h enthält Mitglieder, die nach
Distanzabschätzung nahe bei h liegen. Die Menge an Blättern enthält Mitglieder,
deren IDs numerisch nahe bei der von h liegen. Diese Menge ist in zwei gleichgroße
Hälften unterteilt, in denen jeweils nur Mitglieder liegen, deren ID kleiner bzw. größer
ist, als die von h. [om]
- 37 -
3. Konzept
Das Scribe Multicast-Protokoll nutzt Pastry als Overlay-Netzwerk. Daher ist die
Steuerungstopologie die gleiche wie in Pastry. Die Nachbarn eines Mitglieds auf der
Steuerungstopologie berücksichtigen dessen Routing-Tabelle sowie seine Menge an
Nachbarn und Blättern. Die Unicast-Pfade zwischen Mitgliedern werden dann durch
feste Regeln definiert. Eine Nachricht mit einer Ziel-ID y wird zu einem Mitglied
geleitet, dass y als ID hat. Wenn kein solches Mitglied im Overlay-Netz existiert, so
wird die Nachricht an Mitglied z geleitet, dessen ID y numerisch am Nächsten ist.
Dieses Routing erfolgt durch das Weiterleiten der Nachricht an ein anderes Mitglied
in der Routing-Tabelle, das ein längeres Präfix mit y gemein hat als das
weiterleitende Mitglied selbst. Falls kein solches Mitglied gefunden werden kann, so
wird die Nachricht an eines aus der Menge der Blätter weitergeleitet, das numerisch
näher an y liegt. Eine Multicast-Gruppe in Scribe besteht typischerweise aus einer
Teilmenge der Mitglieder eines Pastry-Netzwerks (sh. Abb. 3-6). Jede MulticastGruppe hat ihre eigene ID, auch Themen-ID (engl. topics) genannt. Das Mitglied,
dessen ID am nächsten an der Themen-ID liegt, wird RP (Rendezvous Punkt) für die
Gruppe. Die Datentopologie im Scribe-Netzwerk ist dann die Vereinigung der PastryUnicast-Pfade von allen Mitgliedern der Scribe-Gruppe zum RP. Die Beschaffenheit
des Datenpfades wird somit während der Beitritts-Prozedur der einzelnen Mitglieder
definiert. [om]
Abbildung 3 - 6: Scribe Aufbau
Um einer Scribe-Gruppe beizutreten, muss ein neues Mitglied erst dem PastryNetzwerk beigetreten sein. Dessen Anmeldevorgang wird hier nicht weiter
beschrieben. Wenn ein Mitglied n dann einer Scribe-Gruppe beitreten möchte,
schickt es eine Anfrage über das Pastry-Netzwerk zur Themen-ID der Gruppe. Diese
Anfrage wird von Pastry automatisch zum RP der Gruppe geleitet. Alle Mitglieder auf
- 38 -
3. Konzept
dem Unicast-Pfad von n zum RP, die noch nicht Mitglieder des MulticastDatenbaumes sind, fügen sich selbst zum Datenbaum hinzu. [om]
3.2.4 SplitStream
Splitstream [ss] ist eine Weiterentwicklung von Scribe und wurde vor allem für Media
Streaming entwickelt. Es geht primär darum, den Inhalt in Streifen zu schneiden, und
diese dann über knotendisjunkte Bäume zu verteilen. Knotendisjunkt nennt man zwei
Mengen, wenn es keine Knoten gibt, der in beiden enthalten ist.
Ein gewaltiger Vorteil von SplitStream ist, dass es die Bandbreite der einzelnen
Mitglieder berücksichtigt, oder die Mitglieder selbst über ihre Bandbreite entscheiden.
Die meisten Multicast-Protokolle benutzen einen einzigen Baum für die
Datenübertragung. Was die Last auf die einzelnen Knoten angeht, ist natürlich dies
nicht optimal, da es nicht ausgeglichen ist. So müssen die Blätter eines Baumes die
empfangenen Inhalte nicht an andere Mitglieder leiten. Dafür sind nur die
innenliegenden Knoten des Baumes zuständig. In einem ausgeglichenen Baum
steigt der prozentuale Anteil der Blätter gegenüber den Knoten. In einem binären
Baum sind mehr als 50% der Knoten Blätter. In einem Baum der Stelligkeit 16 sind
es schon über 90%. Es sind also nur 10% der Mitglieder des Baumes dafür
zuständig, die Daten weiterzuleiten. Die eingehende Bandbreite ist für alle Knoten im
Baum dieselbe. Die ausgehende Bandbreite ist jedoch für die Blätter 0, wo sie für die
innenliegenden Knoten im letzten Fall das 16-fache der eingehenden Bandbreite
beträgt. Selbst in einem binären Baum, der in den meisten Fällen unpraktikabel tief
ist, wäre sie noch doppelt so hoch wie die eingehende Bandbreite. Gerade der
Upstream ist bei aktuellen DSL-Verbindungen aber beschränkt und bei Benutzern mit
Modem oder ISDN sind breitbandige Datenübertragungen sowieso nur begrenzt
möglich. [op]
Wie im Kapitel 2.5 beschrieben wurde, wurde SplitStream entwickelt, um diese
Ungleichheit zu überwinden und alle Mitglieder einer kooperativen Umgebung
gleichmäßig, mit Rücksicht auf ihre individuellen Fähigkeiten, einzubinden. Dazu wird
der Inhalt in n Streifen geschnitten und über knotendisjunkte Bäume verteilt (sh. Abb.
3-7). Analog zum wahren Leben wird eine Struktur aus vielen Bäumen ein Wald
genannt. Jedes Mitglied in SplitStream ist ein innenliegender Knoten in exakt einem
Baum und ein Blatt in allen anderen. So erhält jedes Mitglied den gesamten Inhalt.
Jeder innenliegende Knoten im Wald sollte nun den Streifen, den er selbst
weiterleitet, an n andere Mitglieder leiten. Die eingehende Bandbreite ist daher gleich
der ausgehenden Bandbreite für jedes Mitglied im Wald. Einzelne Knoten können
jetzt ihre eingehende Bandbreite kontrollieren, indem sie nicht alle der n Streifen
abonnieren. Genauso können sie ihre ausgehende Bandbreite kontrollieren, indem
sie die Zahl der Söhne, die sie zulassen, verringern. Somit kann SplitStream sich den
Ressourcen der einzelnen Mitglieder anpassen. [op]
SplitStream
bietet
eine
generische
Infrastruktur
zum
Verteilen
von
bandbreitenintensiven Inhalten über Multicast. Eine Anwendung, die SplitStream
nutzen will, muss selbst entscheiden, wie die Inhalte kodiert und in Streifen
geschnitten werden. SplitStream erstellt nur den Multicast-Wald für die Streifen unter
Berücksichtigung der Bandbreitenbeschränkungen der einzelnen Knoten/Mitglieder.
[op] Eine Anwendung muss:
- 39 -
3. Konzept
•
den Inhalt so kodieren und in Streifen schneiden, dass jeder Streifen ungefähr
dieselbe Bandbreite benötigt.
•
sicherstellen, dass jeder Streifen ungefähr die gleiche Menge
Informationen enthält und es keine Hierarchie unter den Streifen gibt.
•
einen Mechanismus bereitstellen um den zwischenzeitlichen Verlust von
Streifen zu tolerieren.
an
Um den letzten Punkt zu erfüllen, könnte eine Anwendung explizit Algorithmen
bereitstellen, um nicht empfangene Daten von anderen Mitgliedern des Netzes zu
holen. Sie kann aber genauso gut Redundanzen in den einzelnen Streifen einfügen,
so dass verlorene Streifen aus einer Teilmenge der anderen Streifen berechnet
werden können. Dadurch braucht jeder Streifen etwas mehr Bandbreite als B/n,
wobei B die Bandbreite des gesamten Inhalts ist. Dafür kann der Inhalt aus weniger
als n Streifen zurück gewonnen werden. Beispielsweise könnte ein Video mit Multiple
Description Coding (MDC) kodiert und die einzelnen Beschreibungen als Streifen
versendet werden. Aus jeder beliebigen Teilmenge kann das Video gewonnen
werden. Die Qualität des Videos steigt proportional zur Anzahl der empfangenen
Streifen. Die Übertragung reisst auch nicht ab, wenn einige Mitglieder ausfallen, und
ein Mitglied von einem der Bäume abgeschnitten ist. Es wird während der Reparatur
das Video nur in geringfügig schlechterer Qualität wiedergegeben.
Diese Art der Kodierung erlaubt es Mitgliedern mit geringerer Bandbreite auch,
explizit weniger Streifen zu abonnieren, und damit das Video in geringerer Qualität
abzuspielen. Bei anderen Multicast - Protokollen mit nur einem Baum ist hier ein
völlig neuer Stream nötig, um verschiedene Qualitäten anzubieten. [op]
Eine andere Möglichkeit ist das Multicasting von Dateien, wo jeder Datenblock mit
Erasure - Codes kodiert werden kann, um n Blöcke zu generieren, bei denen nur
eine Teilmenge der n Blöcke nötig ist, um den Originalblock wieder herzustellen.
Dann wird jeder Streifen genutzt, um einen anderen der n Blöcke zu versenden.
Mitglieder müssten alle Streifen abonnieren, und wenn ein Streifen ausfällt, werden
die Daten durch die Redundanzen aus den anderen Blöcken generiert. [op]
- 40 -
3. Konzept
Abbildung 3 - 7: SplitStream Baum
3.3 Das OSGi-Schichtenmodell
Die OSGi Framework-Spezifikation ist in mehrere logische Schichten aufgeteilt. Jede
Schicht fasst zusammengehörige Aufgaben bzw. Verantwortlichkeiten zusammen
(sh. Abb. 3-8).
Abbildung 3 - 8: OSGi-Schichten
(Quelle: osgi.org)
•
Module-Schicht: Die Module-Schicht definiert das Bundle als grundlegende
Modularisierungseinheit innerhalb der OSGi Service Plattform.
•
Lifecycle-Management-Schicht: Die Schicht spezifiziert, welche Zustände ein
Bundle während seines Lebenszyklus innerhalb der OSGi Service Plattform
besitzen kann.
•
Security-Schicht: Hier werden sicherheitsrelevante Aspekte spezifiziert wie
bspw. der Umgang mit signierten Bundles und die Möglichkeit zur
Einschränkung der Ausführungsrechte einzelner Bundles.
- 41 -
3. Konzept
•
Service-Schicht: Die Service-Schicht spezifiziert ein allgemeines ServiceModell, in dem Serivces systemweit über eine Service Registry verfügbar
gemacht werden können.
•
Execution environment: Alle Java-Umgebungen wie J2SE, CDC, CLDC,
MIDP, usw.
3.3.1 Module-Schicht
Die Module-Schicht ist die unterste logische Schicht in der OSGi-FrameworkSpezifikation. Sie definiert das dem Framework zugrunde liegende Modulkonzept.
Darin wird das Bundle als die Einheit spezifiziert, die eigenständig im Framework
installiert und deinstalliert werden kann.
Technisch betrachtet ist ein Bundle ein Java-Archiv (jar-Datei), das die zur
Implementierung einer gewünschten Funktionalität erforderlichen Klassen und
Ressourcen enthält.
Zusätzlich zum eigentlichen Inhalt besitzt ein Bundle ein Bundle Manifest, in dem
weitere Informationen über das Bundle, wie Namen oder die benötigten Packages,
beschrieben werden. Das Bundle Manifest ist die Datei MANIFEST.MF im
Verzeichnis META-INF in dem jar-Archiv. Die Informationen aus dem Bundle
Manifest werden vom Framework verwendet, um das Bundle korrekt betreiben zu
können [osp].
Manifest-Version: 1.0
Bundle-Activator: com.java.example.HelloActivator
Bundle-Name: Example plugin
Bundle-Description: Example Bundle
Bundle-Vendor: SWT
Bundle-Version: 0.0.1
Import-Package: org.osgi.framework
Folgende Eigenschaften sind zwingend in der Manifest-Datei anzugeben:
•
Manifest-Version: Zwingend notwendig für ein Manifest-File ist die Version.
•
Bundle-Name: Name des Bundles.
•
Bundle-Activator: Diejenige Klasse, die das Interface BundleActivator
implementiert.
•
Import-Package: Importiert ein Paket, das von einem anderen Bundle
exportiert wurde. Hier kann auch die Version spezifiziert werden. Zwingend ist
hier org.osgi.framework.
- 42 -
3. Konzept
Optional sind:
•
Bundle-SymbolicName: Eindeutiger Name des Bundles, wird verwendet für
Bundle-Repositories.
•
Export-Package: Gibt an, welche Pakete von diesem Bundle exportiert
werden. Andere Bundles können diese verwenden, indem sie sie importieren.
•
Bundle-Description: Beschreibung des Bundles.
•
Bundle-Version: Version des Bundles. Bildet mit dem SymbolicName eine
eindeutige ID.
•
Bundle-Classpath: Verwendet in das Bundle eingebettete JARs, so kann
dieses Property dazu verwendet werden, um den Classpath des Bundles mit
diesen zu erweitern.
•
Bundle-Source: Pfad zum Source-JAR des Bundles, falls vorhanden.
•
Bundle-DocURL: Pfad zur Dokumentation.
•
Bundle-Vendor: Hersteller.
•
Bundle-Copyright: Copyright-Angaben.
Eine besondere Eigenschaft der OSGi Service Platform ist, dass die Abhängigkeiten
zwischen Bundles explizit verwaltet werden. So sind die Packages eines Bundles
zunächst für andere Bundles nicht sichtbar. Um sie in anderen Bundles nutzen zu
können, müssen sie erst durch das implementierende Bundle exportiert werden. Um
ein Package in einem anderen Bundle nutzen zu können, muss dieses Bundle durch
das entsprechende Package dann explizit importiert werden. Die beiden Operationen
werden durch die entsprechenden Headers innerhalb der Manifest-Dateien erledigt.
3.3.2 Die Lifecycle-Management-Schicht
In der Lifecycle-Management-Schicht werden die dynamischen Aspekte von Bundles
festgelegt. Insbesondere werden die Zustände definiert, in denen sich ein Bundle
während seines Lebenszyklus innerhalb des OSGi Frameworks befinden kann.
Jedes Bundle kann installiert, gestartet, gestoppt und wieder deinstalliert werden (sh.
Abb. 3-9). Zusätzlich kann es während der Laufzeit aktualisiert (update) werden.
Diese Zustände werden manuell durch entsprechende Kommandos gestartet. Es
existieren auch verschiedene Management Agents, die die Manipulation von den
Zuständen steuern. Wie ein Management Agent jedoch den Zugriff auf das
Framework ermöglicht, ist in der OSGi Service Platform Specification nicht festgelegt.
- 43 -
3. Konzept
Abbildung 3 - 9: Zustandsdiagramm eines Bundles
(Quelle: wimpi.coalevo.net)
3.3.3 Die Service-Schicht
Die Service-Schicht legt fest, wie innerhalb des Frameworks Objekte in Form von
OSGi Services verwendet werden. Ein OSGi Service ist ein einfaches Java-Objekt,
das an einer zentralen Stelle (Server Registry) unter einem Interfacenamen
angemeldet wird. Dort kann es von anderen Bundles, die den Service nutzen
möchten, über den bei der Anmeldung angegebenen Namen abgefragt und
verwendet werden. Für gewöhnlich wird ein OSGi Service unter dem Namen des
Interfaces registriert, das die öffentlichen Methoden des Service definiert. Dieses
Interface wird auch als Service Interface bezeichnet. Services können innerhalb des
OSGi Frameworks jederzeit an der Service Registry registriert und wieder
abgemeldet werden. Das bedeutet, dass Nutzer dieser Services immer damit
rechnen müssen, dass ein Service nicht mehr zur Verfügung steht. Um das Arbeiten
mit dynamischen Services zu ermöglichen bzw. zu vereinfachen, stehen mit Service
Listenern, dem Service Tracker und den Declarative Services Möglichkeiten zur
Verfügung, die ein Bundle nutzen kann, um auf Veränderungen der Services zu
reagieren.[osp]
3.3.4 Die Security-Schicht
Die Security-Schicht ist ein Bestandteil des Security-Konzeptes der OSGi Services
Plattform, der es ermöglicht, die Ausführungsrechte einzelner Bundles gezielt
einzuschränken. Sie basiert auf dem Java-Sicherheitsmodell, das erweitert wurde,
um es an die speziellen Anforderungen von OSGi anzupassen. Dadurch können die
Ausführungsrechte für jedes Bundle individuell eingestellt werden.
- 44 -
3. Konzept
3.3.5 Die Framework Services
Die OSGi Framework Specification definiert fünf Framework Services, die die
Implementierung von Management Agents unterstützen. Die ersten beiden Services
implementieren OSGi-spezifische Dienste, die grundsätzlich in Management Agents
benötigt werden und in der zugrunde liegenden JAVA-Umgebung nicht vorhanden
sind:
•
Package Admin Service: Der Package Admin Service spezifiziert einen Dienst,
über den Management Agents die Package-Abhängigkeiten zwischen
installierten Bundles abfragen können.
•
Start Level Service: Über den Start Level Service kann ein Management Agent
die relative Start- bzw. Stopp-Reihenfolge von Bundles innerhalb des OSGi
Frameworks abfragen. Der Start-Level kann für jedes installierte Bundle sowie
für das Framework selber individuell eingestellt werden.
Folgende drei Services stellen Anpassungen bzw. Erweiterungen von bereits in der
Java-Laufzeitumgebung verfügbare Dienste dar:
•
Conditional Permission Admin Service: Dieser Service beschreibt die OSGiErweiterungen des Java-Security-Frameworks. Es definiert eine API zum
Anlegen und Verwalten von Berechtigungen auf Bundle-Ebene und stellt
sicher, dass Änderungen der Berechtigungen wirksam werden, ohne dass das
Bundle oder die JAVA-VM neu gestartet werden muss.
•
Permission Admin Service: Der Permission Admin Service dient ebenfalls der
Verwaltung von Berechtigungen, gilt aber als veraltet.
•
URL Handler Service: Der URL Handler Service ermöglicht es Bundles,
eigene URL Handler für die Klasse java.net.URL im System anzumelden, so
dass einmal installierte URL Handler wieder entfernt werden können.
- 45 -
4. Realisierung
4. Realisierung
Nachdem die theoretischen Aspekte von SplitStream eingeführt wurden, wird in
diesem Kapitel anhand eines Java-Beispiels gezeigt, wie eine entsprechende
Anwendung entsteht. Das Beispiel beschreibt, wie man einen SplitStream Client
erzeugt, ihn an ein schon bestehendes Pastry-Netz bindet und wie man die Daten in
Stripes aufsplitten kann.
Das so enstandene Programm wird als ein OSGi Plugin in das Projekt eingebunden.
Die Entwicklung eines Plugins wird auch als weiteres Beispiel in diesem Kapitel
geschildert. Die Einbindung des Bundles erfolgt in das Oscar Framework, was eine
freie Implementierung des OSGi-Standards ist.
Da die entwickelte Applikation als eine Erweiterung des SIP Communicators
funktionieren soll, wird hier auch gezeigt, wie man in den Client eigene Module
einbinden kann.
Zuletzt werden die konkreten Implementierungen beschrieben. Dies sind der Peer-toPeer Live Video Streaming Proxy und dessen Einbindung in den SIP Communicator.
4.1 Erstellen eines SplitStream Clients
Wie im vorigen Kapitel erläutert wurde, nutzt SplitStream separate Scribe-Multicast
Bäume (sh. Abb. 4-1), um die n Streifen zu verteilen. Dazu nutzt es die
Eigenschaften von Pastry aus, um knotendisjunkte Bäume zu erstellen (sh.Abb. 4-2).
Da Pastry die Pakete immer an Mitglieder weiterleitet, die ein längeres Präfix mit der
Ziel-ID gemein haben, werden die Pakete meist im ersten Schritt schon an ein
Mitglied geleitet, dessen erstes Zeichen mit der Themen-ID übereinstimmt. Da jeder
Scribe-Baum durch die Routen aller Mitglieder zur Themen-ID erstellt wird, kann
davon ausgegangen werden, dass sämtliche innere Knoten eines Baumes
mindestens das erste Zeichen mit der Themen-ID gemein haben. Es kann also
angenommen werden, dass die inneren Knoten aller Scribe-Bäume disjunkt sind,
wenn für die verschiedenen Streifen einfach Themen-IDs gewählt werden, die sich
an der ersten und damit wichtigsten Stelle unterscheiden. Der dadurch entstehende
Wald aus Scribe-Bäumen ist disjunkt, was die inneren Knoten angeht. [op]
Abbildung 4 - 1: SplitStream, einzelne Stripes
- 46 -
4. Realisierung
Abbildung 4 - 2: SplitStream mit zwei Stripes
SplitStream ist Teil von FreePastry ab Version 1.3.1. Dieses ist OpenSource unter
einer BSD-ähnlichen Lizenz und zu bekommen unter http://freepastry.rice.edu.
FreePastry basiert auf Java und ist daher plattformübergreifend einsetzbar. [op]
Im Folgenden wird anhand eines Programmierbeispiels der Einsatz von SplitStrem
erläutert. Man benötigt die FreePastry Bibliothek (FreePastry-x.x.jar), um die
entsprechenden Klassen zu benutzen.
Die wichtigen Punkte hier sind, wie man
•
Einen SplitStreamClient erzeugt. Der Client wird benötigt, um überhaupt Daten
von SplitStream zu bekommen.
•
Einen Channel erzeugt oder sich dort anhängt.
•
Sich abonniert (Subscribe), um Daten von einem SplitStream Channel zu
bekommen.
•
Daten über die einzelnen Stripes verschickt (Publish).
•
Daten empfängt (Receive).
Das Beispiel besteht aus zwei Dateien – MySplitStreamClient.java und
SplitStreamTutorial.java. In der Ersten wird die Funktionalität des SplitStream Clients
implementiert und in der Zweiten wird eine kleine Testumgebung entwickelt, um eine
Kommunikation zwischen mehreren Knoten zu simulieren.
Das SplitStream – Interface besitzt zwei Methoden. joinFailed() wird aufgerufen,
wenn ein Fehler beim Stripe-Abonnieren auftritt. In diesem Fall sollte man erneut
- 47 -
4. Realisierung
versuchen, sich zu abonnieren. Die Zweite Methode deliver() wird aufgerufen, wenn
Daten über den Stripe s ankommen (sh. Listing 4-1).
public interface SplitStreamClient {
/* This is a call back into the application
to notify it that one of the stripes was unable to to
find a parent, and thus unable to recieve data.
@param s The stripe which the join failed on
*/
public void joinFailed(Stripe s);
/* Is called when data is received on a stripe
which this client has registered interest
@param data The data that was received
@param s The stripe the data as received on
*/
public void deliver(Stripe s, byte[] data);
Listing 4 -1: SplitStream Interface
In der MySplitStreamClient Klasse werden einige Variablen deklariert, die hier
aufgelistet werden. DATA_LENGTH gibt die Größe in Bytes der zu versendenden
Daten an. NUM_PUBLISHES steht für die Anzahl der Wiederholungen beim Senden.
Die ChannelId Klasse entspricht dem Topic (das Thema), unter welchem ein Channel
entsteht. mySplitStream stellt die Implementierung von SplitStream dar. myStripes
beinhaltet alle Stripes eines Channels. Die RandomSource Klasse wird benötigt, um
zufällige Daten als Payload zu erzeugen. Die Daten, die versendet werden, werden
als erstes in ein Array gepackt, wobei die ersten zwei Bytes für die Sequenznummer
und die Stripe-ID reserviert werden. Die restlichen 8 Bytes werden mit Random Data
gefüllt. Es werden 10 Nachrichten über alle 16 Stripes verschickt, was eine
Gesamtmenge von 160 Nachrichten entspricht (sh. Listing 4-2).
- 48 -
4. Realisierung
// The lenght of a message in bytes.
public static final int DATA_LENGTH = 10;
// The number of messages to publish.
public static final int NUM_PUBLISHES = 10;
byte seqNum = 0;
// My handle to a SplitStream impl.
SplitStream mySplitStream;
// The Id of the only Channel we are subscribing to.
ChannelId myChannelId;
// The channel.
Channel myChannel;
// The stripes... acquired from myChannel.
Stripe[] myStripes;
// Data source...
protected RandomSource random;
Listing 4 – 2: Eigenschaften der MySplitStreamClient Klasse
Jetzt müssen die Variablen initialisiert werden. Dies geschieht in dem Konstruktor
MySplitStreamClient() (sh. Listing 4-3).
- 49 -
4. Realisierung
public class MySplitStreamClient
implements SplitStreamClient, Application {
public MySplitStreamClient(Node node) {
this.endpoint = node.buildEndpoint(this, "myinstance");
// use this to generate data
this.random = endpoint.getEnvironment()
.getRandomSource();
// construct Scribe
mySplitStream =
new SplitStreamImpl(node,"splitStreamTutorial");
// The ChannelId is built from a normal PastryId
Id temp = new PastryIdFactory(node.getEnvironment())
.buildId("my channel");
// construct the ChannelId
myChannelId = new ChannelId(temp);
// now we can receive messages
endpoint.register();
}
Listing 4 – 3: Initialisieren der Variablen
Zuerst wird ein Endpoint mit Hilfe von Node erstellt. Dies erlaubt, dass man mehr als
nur eine Implementierung gleichzeitig an einem Node starten kann. Sie können
untereinander kommunizieren, nur wenn sie den gleichen instance-String haben. Im
nächsten Schritt wird Random Data erzeugt und anschließend die SplitStream
Implementierung. Dann wird die ChannelId initialisiert mit dem Hashwert des „my
channel“ – String. Mit Hilfe der register() - Funktion wird der Endpunkt registriert und
ist bereit, Daten zu empfangen.
Die subscribe() Methode wird benötigt, damit sich der Node an einem Channel
(myChannelId) anhängt (sh. Listing 4-4). So wird der Knoten einen internen
Teilnehmer des Kanals und ein innenliegender Knoten eines Baums. Allein das reicht
aber nicht aus. Man muss sich explizit für jeden Stripe abonnieren, um die Daten zu
empfangen, die man benötigt.
- 50 -
4. Realisierung
public void subscribe() {
/* attaching makes you part of the Channel, and
volunteers to be an internal node of one of the trees */
myChannel = mySplitStream.attachChannel(myChannelId);
/* subscribing notifies your application when data comes
through the tree */
myStripes = myChannel.getStripes();
for (int curStripe = 0; curStripe < myStripes.length;
curStripe++)
{
myStripes[curStripe].subscribe(this);
}
}
Listing 4 – 4: Anhängen an einem Channel
Die ID-Nummer jedes Stripes ist identisch mit der ID des Kanals. Unterschiedlich ist
nur die erste Stelle der Nummer. Sie entspricht der Nummer des Stripes. Zum
Beispiel, wenn die ChannelID <0x26F8A8..> ist, werden die Stripes 0 bis 15 die
Nummern <0x06F8A8>, <0x16F8A8> bis <0xF6F8A8> haben.
In einer Anwendung werden oft aber nicht alle Stripes benötigt. Die Schwierigkeit
besteht darin, dass man ein deterministisches Verfahren entwickelt, mit dessen Hilfe
jeder Knoten die gleiche Menge an Daten bekommt. Dies bedeutet, dass man sich
am ersten Kanal für die Stripes 0 bis 3 abonniert, beim Zweiten 4 bis 7, usw. So ist
der Knoten ein Blatt (Leaf) der anderen Bäume und selber ein innerlicher Knoten von
myChannel, welcher Daten weiterleitet. In der Praxis werden häufig Verfahren
vorgeschlagen, die auf Hashwerten basieren.
Wenn man selbst Daten über Multicast publizieren möchte, dann wird das in der
publish() Methode gemacht (sh. Listing 4-5). Die Daten werden in die oben erläuterte
Struktur gepackt – Bit 1 für die Sequenznummer und Bit 2 für die Stripe-ID, über
welche die Daten verschickt werden. Die restlichen 8 Bits sind für die Random Data
reserviert. Das Absenden geschieht einfach, indem man über den Stripe die
publish(data) Methode aufruft. Das gleiche macht man für alle 16 Stripes mit Hilfe der
for - Schleife.
- 51 -
4. Realisierung
public void publish() {
for (byte curStripe = 0; curStripe < myStripes.length;
curStripe++) {
// format of the data:
// first byte: seqNum
// second byte: stripe
// rest: random
byte[] data = new byte[DATA_LENGTH];
// yes, we waste some random bytes here
random.nextBytes(data);
data[0] = seqNum;
data[1] = curStripe;
// print what we are sending
System.out.println("Node
"+endpoint.getLocalNodeHandle()+" publishing
"+seqNum+" "+printData(data));
// publish the data
myStripes[curStripe].publish(data);
}
// increment the sequence number
seqNum++;
// cancel after sending all the messages
if (seqNum >= NUM_PUBLISHES) publishTask.cancel();
}
Listing 4 – 5: Publizieren von Daten
Es wurde am Anfang gesagt, dass die Daten NUM_PUBLISHES Male versendet
werden. Damit dies aber in Zeitabständen passiert, wird ein Timer verwendet. Durch
scheduleMessage() wird gesagt, dass eine PublishContent Nachricht alle 5
Sekunden intern versendet wird (sh. Listing 4-6). Wenn sie ankommt, wird die
deliver() Methode aufgerufen, welche von ihrer Seite publish() aufruft, um die Daten
über die Stripes zu versenden.
- 52 -
4. Realisierung
public void startPublishTask() {
publishTask = endpoint.scheduleMessage(new
PublishContent(),
5000,5000);
}
public void deliver(Id id, Message message) {
if (message instanceof PublishContent) {
publish();
}
}
class PublishContent implements Message {
public int getPriority() {
return Message.MEDIUM_PRIORITY;
}
}
Listing 4 – 6: Festlegen der Zeitabstände zum Versenden
Das Ankommen von Daten über die Stripes wird von der deliver() Methode
abgefangen (sh. Listing 4-7). Sie zeigt den Inhalt mit Hilfe der printData() Methode
an, welche die Daten aus einem Byte-Array nach Integer umwandelt.
/**
* Called whenever we receive a published message.
*/
public void deliver(Stripe s, byte[] data) {
System.out.println(endpoint.getId()+"
deliver("+s+"):seq:"+data[0]+" stripe:"+data[1]+"
"+printData(data)+")");
}
private String printData(byte[] data) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < data.length-1; i++) {
sb.append((int)data[i]);
sb.append(',');
}
sb.append((int)data[data.length-1]);
return sb.toString();
}
Listing 4 – 7: Abfangen der angekommenen Daten
Damit ist die Arbeit für den SplitStreamClient erledigt. Jetzt es bleibt noch die
angekündigte Umgebung, um mehrere Knoten an dem gleichen Host zu erzeugen.
Dies wird in der zweiten Datei - SplitStreamTutorial.java gemacht.
- 53 -
4. Realisierung
public class SplitStreamTutorial {
// this will keep track of our Scribe applications
Vector apps = new Vector();
public SplitStreamTutorial(int bindport,
InetSocketAddress bootaddress, int numNodes,
Environment env, boolean useDirect)
throws Exception {
// Generate the NodeIds Randomly
NodeIdFactory nidFactory = new RandomNodeIdFactory(env);
// construct the PastryNodeFactory
PastryNodeFactory factory;
if (useDirect) {
NetworkSimulator sim = new EuclideanNetwork(env);
factory = new DirectPastryNodeFactory(nidFactory,
sim, env);
} else {
factory = new SocketPastryNodeFactory(nidFactory,
bindport,env);
}
Listing 4 – 8: Vorbereiten der Versuchsumgebung
Am Anfang wird ein Vector vorbereitet, in welchem die neu erzeugten Nodes
abgelegt werden. In dem SplitStreamTutorial – Konstruktor wird die Pastry
NodeFactory initialisiert, welche für das Erzeugen der Nodes zuständig ist (sh. Listing
4-8).
Anschließend werden die Nodes in einer for-Schleife erzeugt und initialisiert. Da ein
Boot-Prozess etwas Zeit benötigt, wird eine halbe Sekunde gewartet, um die nötigen
Nachrichten auszutauschen. Ist der Node gestartet, erzeugt man ein Objekt von
unserer MySpliStreamClient Klasse, welche in dem oben beschriebenen Vektor
hinzugefügt wird (sh. Listing 4-9).
for (int curNode = 0; curNode < numNodes; curNode++) {
/* construct a node, passing the null boothandle on the
first loop will cause the node to start its own ring */
PastryNode node = factory.newNode(bootHandle);
if (bootHandle == null) {
if (useDirect) {
bootHandle = node.getLocalHandle();
} else {
/* This will return null if we there is no node at that
Location */
bootHandle =((SocketPastryNodeFactory)factory).
getNodeHandle(bootaddress);
}
}
- 54 -
4. Realisierung
/* the node may require sending several messages to fully
boot into the ring */
synchronized(node) {
while(!node.isReady() && !node.joinFailed()) {
// delay so we don't busy-wait
node.wait(500);
// abort if can't join
if (node.joinFailed()) {
throw new IOException("Could not join the
FreePastry ring. Reason:" +node.joinFailedReason());
}
}
}
MySplitStreamClient app = new MySplitStreamClient(node);
apps.add(app);
}
Listing 4 – 9: Erzeugen der Nodes
Nachdem der Vektor gefüllt ist, wird in ihm iteriert und von jedem SplitStream Client
die subscribe() Methode aufgerufen, welche das Stripes-Abonieren durchführt (sh.
Listing 4-10). Der erste Client in der Liste ist auch derjenige, der das Multicast
Versenden von Nachrichten erledigt.
// for the first app subscribe then start the
// publishtask
Iterator i = apps.iterator();
MySplitStreamClient app = (MySplitStreamClient)i.next();
app.subscribe();
app.startPublishTask();
// for all the rest just subscribe
while (i.hasNext()) {
app = (MySplitStreamClient) i.next();
app.subscribe();
}
// now, print the tree
env.getTimeSource().sleep(5000);
Listing 4 – 10: Starten der Nodes
Startet man die Applikation, so sieht man am Anfang das Erzeugen von den 10
Nodes. Wie schon gesagt wurde, ist der erste Node derjenige, der die Nachrichten
versenden wird. In diesem Beispiel ist es <0x7A49D8..> . Der Node versendet die
Random - Daten über alle 16 Stripes, hier fett gedruckt. Gleich danach sieht man,
dass die anderen Nodes beginnen, die Nachrichten zu bekommen. Zum Beispiel,
jeder der für Stripe 0 abonniert ist, bekommt die Daten, die an diesem Stripe
- 55 -
4. Realisierung
versendet wurden. Hier ist nur ein Ausschnitt gezeigt, da die Gesamtzahl der
Nachrichten 160 beträgt (sh. Listing 4-11).
Finished
Finished
Finished
Finished
Finished
Finished
Finished
Finished
Finished
Finished
creating
creating
creating
creating
creating
creating
creating
creating
creating
creating
new
new
new
new
new
new
new
new
new
new
node
node
node
node
node
node
node
node
node
node
TLPastryNode[DNH
TLPastryNode[DNH
TLPastryNode[DNH
TLPastryNode[DNH
TLPastryNode[DNH
TLPastryNode[DNH
TLPastryNode[DNH
TLPastryNode[DNH
TLPastryNode[DNH
TLPastryNode[DNH
Node [DNH <0x7A49D8..>] publishing
62,66,31,-50,37,-21,44,97
Node [DNH <0x7A49D8..>] publishing
49,-69,82,15,-113,-84,-7,4
Node [DNH <0x7A49D8..>] publishing
104,-15,38,98,68,-39,-29,61
Node [DNH <0x7A49D8..>] publishing
-48,-5,30,-52,-47,-31,-86,67
<0x7A49D8..>]
<0x1526D4..>]
<0xE109BA..>]
<0x710D8A..>]
<0xAB9A4C..>]
<0x78E6F2..>]
<0x6FCB89..>]
<0x199612..>]
<0xA3160F..>]
<0xA05351..>]
0 0,0,
0 0,1,
0 0,2,
0 0,3,
………
Node [DNH <0x7A49D8..>] publishing 0 0,15,
5,13,117,93,-77,81,-12,33
<0x1526D4..> deliver(Stripe [StripeId <0x06F8A8..>]):
seq:0 stripe:0 0,0,62,66,31,-50,37,-21,44,97)
<0x1526D4..> deliver(Stripe [StripeId <0x16F8A8..>]):
seq:0 stripe:1 0,1,49,-69,82,15,-113,-84,-7,4)
<0x1526D4..> deliver(Stripe [StripeId <0x86F8A8..>]):
seq:0 stripe:8 0,8,46,20,24,43,26,-32,-80,67)
<0x710D8A..> deliver(Stripe [StripeId <0x86F8A8..>]):
seq:0 stripe:8 0,8,46,20,24,43,26,-32,-80,67)
<0x6FCB89..> deliver(Stripe [StripeId <0x46F8A8..>]):
seq:0 stripe:4 0,4,-104,53,125,-23,-44,-8,88,-108)
<0x6FCB89..> deliver(Stripe [StripeId <0x56F8A8..>]):
seq:0 stripe:5 0,5,47,-54,117,80,-10,-90,-116,45)
Listing 4 – 11: Programmausgabe
Dieses Beispiel wurde von der offiziellen Seite von freepastry.org entnommen.
Detaillierte Informationen und andere Programmierbeispiele kann man auch von dort
erhalten.
- 56 -
4. Realisierung
4.2 Entwicklung eines OSGi Pugins
In diesem Kapitel werden anhand einiger Programmierbeispiele die grundlegenden
Funktionalitäten des OSGi Frameworks vorgestellt.
Als erstes wird ein „Hello World“ – Bundle erzeugt, welches ein einziges Package mit
genau einer Klasse Bundle-Aktivator enthält. Der Bundle-Aktivator implementiert die
Ausgabe „Hello World“, die beim Bundle-Start erfolgt. Zusätzlich wird beim Stoppen
vom Bundle die „Goodbye World“- Nachricht ausgegeben.
package com.sample.helloworld;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
public class Activator implements BundleActivator {
public void start(BundleContext context) throws Exception
{
System.out.println("Hello world");
}
public void stop(BundleContext context) throws Exception
{
System.out.println("Goodbye World");
}
}
Listing 4 – 12: Die Activator – Klasse
Die Activator-Klasse besitzt zwei Methoden start() und stop(). Die start()-Methode
wird aufgerufen, wenn das Bundle vom OSGi Framework aufgerufen wird. Analog
dazu wird die stop()-Methode beim Stoppen aufgerufen (sh. Listing 4-12).
Die entsprechende Manifest-Datei sieht wie folgt aus:
Manifest-Version: 1.0
Bundle-Activator: com.sample.helloworld.Activator
Bundle-Name: Example plugin
Bundle-Description: Example Bundle
Bundle-Vendor: SWT
Bundle-Version: 0.0.1
Import-Package: org.osgi.framework
Listing 4 – 13: Manifest-Datei
Als nächstes wird die Quelltextdatei kompiliert, vorausgesetzt, sie liegt im
Verzeichnis c:\classes. Anschließend werden die kompilierte Datei und die ManifestDatei in ein Archiv gepackt (sh. Listing 4-14).
- 57 -
4. Realisierung
> javac -d c:\classes *.java
> jar cfm example1.jar manifest.mf
-C c:\classes tutorial\example1
Listing 4 – 14: Kompilieren eines Bundles
Um das neue Bundle bekannt zu machen, muss es zuerst im OSGi Framework
installiert werden. Danach ist es bereit, gestartet zu werden. Der Screenshot in
Abbildung 4-3 zeigt an, dass das Bundle unter die Nummer 13 installiert wurde. Mit
dem Kommando start/stop kann das Bundle gesteuert werden.
Abbildung 4 - 3: Oscar GUI
Wie bereits erwähnt, ist OSGi eine Service Oriented Architecture (SOA). Dies bedeutet, dass
bei größeren Projekten eine große Zahl von Bundles vorhanden sein wird. Sie werden auch
unter sich Daten austauschen müssen. Dafür werden die Services gebraucht (sh. Abb. 4-4).
Abbildung 4 - 4: OSGi Services
(Quelle:[sm])
- 58 -
4. Realisierung
Ein Service ist ein Dienst, der von einem Bundle für andere Bundles zur Verfügung
gestellt wird. Dies ermöglicht eine Kommunikation zwischen den einzelnen Bundles.
Im folgenden Beispiel wird das anschaulicher gemacht, indem wir das vorherige
„Hello World“ – Bundle in zwei neue Bundles aufsplitten.
Zuerst definieren wir den Service. Dies geschieht mittels eines Java-Interfaces in der
Datei HelloService.java. Dieses Interface definiert die Schnittstelle nach Außen und
ist als Service Description bekannt (sh. Listing 4-15).
public interface HelloService {
public String sayHello();
}
Listing 4 – 15: Definition vom HelloService-Interface
Die Implementierung des Interfaces geschieht in HalloServiceImpl.java.
public class HelloServiceImpl implements HelloService{
public String sayHello() {
return "Say Hello";
}
}
Listing 4 – 16: Implementierung des HelloService-Interfaces
Die einzige Methode sayHello() wird überschrieben und liefert einen String zurück.
Wie
bereits
erwähnt,
braucht
jedes
Bundle
einen
Activator
–
HelloServiceActivator.java. Beim Starten des Bundles wird ein Objekt des Typs
HelloServiceImpl erzeugt, auf welches die Interface-Variable helloService verweist.
Anschließend wird der Service beim Service Registry registriert, indem als Name der
Klassenname übergeben wird und die Interface-Variable als Schnittstelle für die von
Außen aufrufenden Bundles (sh. Listing 4-17).
Die stop()-Methode steht dafür, dass beim Stoppen von dem Bundle auch der
Service von der Service Registry abgemeldet wird.
- 59 -
4. Realisierung
public class HelloServiceActivator
implements BundleActivator {
ServiceRegistration helloServiceRegistration;
public void start(BundleContext context)
throws Exception {
HelloService helloService = new HelloServiceImpl();
helloServiceRegistration = context.
registerService(HelloService.class.getName(),
helloService, null);
}
public void stop(BundleContext context) throws Exception
{
helloServiceRegistration.unregister();
}
}
Listing 4 – 17: Definieren von star/stop – Methoden
Von der Seite des Service Providers ist schon alles erledigt, bis auf die ManifestDatei. Wichtig ist das Export-Package-Feld, welches angibt, dass das Package
exportiert wird (sh. Listing 4-18). Dadurch können andere Bundles es importieren und
Daten mit ihm austauschen.
Manifest-Version: 1.0
Bundle-Activator: com.sample.HelloServiceActivator
Bundle-ManifestVersion: 2
Bundle-Name: HelloService Plug-in
Bundle-SymbolicName: com.sample.HelloService
Bundle-Version: 1.0.0
Bundle-Vendor: SWT
Bundle-Localization: plugin
Export-Package: com.sample.service
Import-Package: org.osgi.framework
Listing 4 – 18: Setzen des Export-Package-Feldes in einer Manifest-Datei
Nachdem die Quelltextdateien kompiliert sind und das Package erzeugt ist, kann ein
Verbraucher (Service Requester) das Bundle in seiner Manifest-Datei importieren.
Damit kann er später die exportierten Services abfragen. Man sieht im ImportPackage-Feld den Namen des Packages, welches vorher exportiert wurde (sh.
Listing 4-19). Auf diese Art und Weise kann man bei größeren Projekten vorgehen
und damit bleibt alles modular und übersichtlich.
- 60 -
4. Realisierung
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: HelloWorld Plug-in
Bundle-SymbolicName: com.sample.HelloWorld
Bundle-Version: 1.0.0
Bundle-Activator: com.sample.helloworld.Activator
Bundle-Vendor: SWT
Bundle-Localization: plugin
Import-Package: com.sample.service,
org.osgi.framework
Listing 4 – 19: Setzen des Import-Package-Feldes in einer Manifest-Datei
Da der Consumer wiederum ein Bundle ist, braucht er auch einen Activator. In der
Datei HelloWorldActivator.java findet man die Implementierung des Verbrauchers
(sh. Listing 4-20). Wichtig ist hier das Abrufen des Services. In der start()-Methode
wird eine Service-Referenz implementiert, welche benötigt wird, um auf den HelloService zuzugreifen. Über die Methoden getServiceReference() und getService()
wird das OSGi Framework aufgefordert, die richtige Instanz zu finden und einen
Verweis auf sie mittels des Interfaces (HelloService) zurückzuliefern. Danach kann
die Methode sayHello() aufgerufen werden, welche den „Hello World“-String liefert.
Wird das Bundle gestoppt, so wird in der stop()-Methode auch der geholte Service
wieder freigegeben.
public class Activator implements BundleActivator {
ServiceReference helloServiceReference;
public void start(BundleContext context)throws Exception
{
helloServiceReference= context.
getServiceReference(HelloService.class.getName());
HelloService helloService =(HelloService)context.
getService(helloServiceReference);
System.out.println(helloService.sayHello());
}
public void stop(BundleContext context) throws Exception
{
context.ungetService(helloServiceReference);
}
}
Listing 4 – 20: Implementierung des Consumer-Bundles
Zusammenfassend kann man sagen, dass sich die Verwendung von OSGi als
einfach gestaltet, da die eigentliche Applikation sehr wenig OSGi-spezifischen Code
beinhaltet. Man benötigt nur einen Activator, um das Boot-Verhalten zu kontrollieren.
Aufpassen muss man, wenn man externe Bundles verwendet, da sie jederzeit
verschwinden können. Dafür wird ein ServiceListener empfohlen, der auf solche
- 61 -
4. Realisierung
Ereignisse reagiert. Als Ganzes ist aber OSGi eine hervorragende Plattform, um
Service-orientierte Anwendungen zu entwickeln.
4.3 Erstellen von eigenen Modulen für den SIP Communicator
Der SIP Communicator (SC) ist ein multiprotokollfähiger, frei verfügbarer Instant
Messenger mit dem außerdem Audio- und Videotelefonie möglich ist. Da er komplett
in Java implementiert ist, gehört er zu den wenigen multiprotokollfähigen Instant
Messengern, die auf allen Plattformen laufen. Der Sip Communicator setzt auf das
OSGi Framework, welches das Programmieren neuer Erweiterungen (plugins) sehr
vereinfacht. Der SIP Communicator unterstützt alle gängigen Protokolle bekannter
Instant Messenger, darunter zählen SIP, Jabber, AIM/ICQ, MSN, Yahoo! Messenger,
Bonjour, IRC, RSS.
Da das Projekt ein Open Source Projekt ist, eignet es sich besonders gut zum
Weiterentwickeln und um wichtige Dinge daraus zu lernen. Den Entwicklern steht
eine Plattform zur Verfügung, welche das Einbinden von eigenen Plugins ins Projekt
vereinfacht.
Im folgenden Kapitel wird gezeigt, wie man sein eigenes Plugin entwickelt und zum
Bestandteil des Projekts macht.
Um ein Plugin zu schreiben, benötigt man als erstes den Quelltext des Projekts.
Diesen kann man sich entweder von der Projektseite holen, oder aus der SVN
Repository herunterladen. Um das zweite zu machen, muss man ein Mitglied des
Projekts werden, was aber nur eine kleine Anmeldung benötigt. Im Java-Umfeld
stehen zwei kostenlose und ausgereifte IDEs zur Verfügung - Eclipse und NetBeans.
Hier wurde mit Eclipse gearbeitet, was aber nicht heißt, dass es mit NetBeans viel
anders ist. Damit man mit Eclipse das Subversion Control System benutzen kann,
benötigt man den Subclipse Modul, welcher einen SVN Client darstellt. Wie man das
Modul installiert, kann man von der offiziellen Sip Communicator Seite entnehmen.
Nachdem die Quelldateien in der Eclipse IDE eingebunden sind, kann man mit dem
Erstellen des Plugins beginnen. Die Klassenhierarchie besitzt eine feste Struktur,
wobei für die Plugins das src.net.java.sip.communicator.plugin Directory vorgesehen
ist. Dort kann man auch sein eigenes Package implementieren.
Da wir hier mit dem OSGi Framework arbeiten, meint man mit Package ein OSGi
Bundle. Wie jedes Bundle benötigt unser Plugin einen Activator, welcher
MyPluginActivator.java genannt wird. Für das Package wird auch die entsprechende
Manifest-Datei benötigt, hier myplugin.manifest.mf, welche den Bundle-Activator, die
externen Bibliotheken und andere Bundlebeschreibungen angibt (sh. Listing 4-21).
- 62 -
4. Realisierung
Bundle-Activator:
net.java.sip.communicator.plugin.exampleplugin.MyPluginActiv
ator
Bundle-Name: Example plugin
Bundle-Description: An example showing how to make plugins
Bundle-Vendor: sip-communicator.org
Bundle-Version: 0.0.1
Import-Package: org.osgi.framework,
net.java.sip.communicator.util,
net.java.sip.communicator.service.contactlist,
net.java.sip.communicator.service.contactlist.event,
net.java.sip.communicator.service.gui,
net.java.sip.communicator.service.gui.event,
net.java.sip.communicator.service.protocol,
javax.swing,
javax.swing.event,
javax.swing.table,
javax.swing.text,
javax.swing.text.html,
javax.accessibility,
javax.swing.plaf,
javax.swing.plaf.metal,
javax.swing.plaf.basic,
javax.imageio,
javax.swing.filechooser,
javax.swing.tree,
javax.swing.undo,
javax.swing.border
Listing 4 – 21: Manifest-Datei eines Plugins im Sip Communicator
Der BundleActivator hat die Aufgabe, die Plugin-Komponente im OSGi Bundle
Context zu registrieren. Die Klasse ExamplePluginMenuItem ist die eigentliche
Implementation der Funktionalität des Bundles. Sie wird weiter nicht betrachtet, da es
nicht so interessant ist. Wichtiger dagegen sind die Schnittstelles zum Sip
Communicator und der Zeitpunkt des Aufrufs. Mittels des containerFilter wird
festgelegt, dass beim Betätigen der rechten Maustaste über einen Chat-Kontakt der
Pluginname als Menüeintrag erscheint. Über bc.registerService() wird die
Komponente registriert (sh. Listing 4-22).
- 63 -
4. Realisierung
package net.java.sip.communicator.plugin.exampleplugin;
import java.util.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.util.*;
import org.osgi.framework.*;
public class MyPluginActivator implements BundleActivator
{
public void start(BundleContext bc) throws Exception
{
ExamplePluginMenuItem examplePlugin = new
ExamplePluginMenuItem();
Hashtable<String, String> containerFilter
= new Hashtable<String, String>();
containerFilter.put(
Container.CONTAINER_ID,
Container.
CONTAINER_CONTACT_RIGHT_BUTTON_MENU.getID());
bc.registerService(PluginComponent.class.getName(),
examplePlugin,containerFilter);
}
public void stop(BundleContext bc) throws Exception
{
}
}
Listing 4 – 22: Implementieren des BundleActivators
Da der Sip Communicator aus mehreren Modulen besteht, muss eine bestimmte
Reihenfolge existieren, wie die einzelnen Module kompiliert bzw. ausgeführt werden.
Dafür wird Ant eingesetzt, was ein Java-basiertes Werkzeug zum automatisierten
Erzeugen von Programmen aus Quelltext darstellt. Damit erfüllt es den gleichen
Zweck wie das sehr verbreitete Programm make, nämlich die automatisierte
Erstellung von installierbaren Software-Paketen aus existierendem Quelltext,
Bibliotheken und sonstigen Dateien. Gesteuert wird Ant durch eine XML-Datei, die so
genannte Build-Datei. Sie heißt standardmäßig build.xml. In der Build-Datei wird ein
Projekt definiert. Dies ist das Wurzelelement der XML-Datei. Zu einem SoftwareProjekt sollte genau eine Build-Datei und damit genau ein Ant-Project gehören. Das
Ant-Projekt enthält Targets. Diese sind vergleichbar mit Funktionen in
Programmiersprachen und können von außen, zum Beispiel vom Entwickler über die
Kommandozeile oder die Entwicklungsumgebung gezielt aufgerufen werden. Die
Targets sollten in ihrer Gesamtheit alle bei der Arbeit mit einem Software-Projekt
anfallenden Tätigkeiten abdecken. Ein Target besteht aus Aufrufen von Tasks. Sie
sind vergleichbar mit Befehlen in Programmiersprachen.
Damit das Beispiel-Bundle auch zusammen mit den anderen Komponenten
kompiliert wird, muss man sein eigenes Target in der build.xml Datei eintragen (sh.
Listing 4-23).
- 64 -
4. Realisierung
<!-- BUNDLE-PLUGIN-EXAMPLE PLUGIN -->
<target name="bundle-plugin-exampleplugin">
<jar compress="false"
destfile="${bundles.dest}/exampleplugin.jar"
manifest="${src}/net/java/sip/communicator/
plugin/exampleplugin/exampleplugin.manifest.mf">
<zipfileset dir= "${dest}/net/java/sip/
communicator/plugin/exampleplugin"
prefix="net/java/sip/communicator/plugin/exampleplugin"/>
</jar>
</target>
Listing 4 – 23: Beschreibung eines Ant - Targets in der build.xml Datei
Die aufgeführten Anweisungen erzeugen eine Jar-Datei unter dem Namen
exampleplugin.jar. Damit der Target bundle-plugin-exampleplugin ausgeführt wird,
muss er zu der Liste mit den anderen Targets hinzugefügt werden, die die
Reihenfolge des Kompiliervorgangs bestimmt (sh. Listing 4-24).
<!--ALL BUNDLES-->
<target name="bundles"
depends="bundle-util,bundle-configuration,bundleconfiguration-slick,
bundle-history,bundle-history-slick,bundle-messagehistory,
bundle-msghistory-slick, bundle-callhistory, bundlecallhistory-slick,
bundle-netaddr,bundle-netaddr-slick,bundle-slickless,
bundle-slick-runner,bundle-sip,bundle-sip-slick,bundlefileaccess,
bundle-fileaccess-slick,bundle-media,bundle-media-slick,
bundle-protocol,bundle-icq,bundle-icq-slick,bundle-mock,
bundle-jabber,bundle-jabber-slick,bundle-swing-ui,
bundle-msn,bundle-msn-slick,
bundle-contactlist,meta-contactlist,meta-contactlist-slick,
bundle-plugin-icqaccregwizz,bundle-plugin-jabberaccregwizz,
bundle-plugin-msnaccregwizz,bundle-plugin-sipaccregwizz,
bundle-version,bundle-version-impl,bundle-shutdown,
bundle-growlnotification, bundle-plugin-exampleplugin"/>
Listing 4 – 24: Festlegung der Kompilierreihenfolge des Ant - Targets
Jetzt muss nur noch dem OSGi Framework mitgeteilt werden, dass beim Starten des
Sip Communicator auch dieses Bundle gestartet werden soll. Dies macht man in der
Konfigurationsdatei felix.client.run.properties, welche den Ablauf beim Starten des
Programms bestimmt. Der Plugin wird unter dem Feld felix.auto.start.67 abgelegt,
wo auch andere Bundles aufgelistet sind (sh. Listing 4-25).
- 65 -
4. Realisierung
felix.auto.start.67= \
reference:file:sc-bundles/accountinfo.jar \
reference:file:sc-bundles/chatalerter.jar \
reference:file:sc-bundles/shutdown.jar \
reference:file:sc-bundles/utoaway.jar \
reference:file:sc-bundles/keybindingChooser.jar \
reference:file:sc-bundles/generalconfig.jar \
reference:file:sc-bundles/dictaccregwizz.jar \
reference:file:sc-bundles/exampleplugin.jar
Listing 4 – 25: Konfigurationsdatei definiert welche Plugins gestartet werden.
4.4 SplitStream Erweiterungen für den SIP Communicator
4.4.1 P2P-Live-Video-Streaming-Proxy
Der P2P-Live-Video-Streaming-Proxy ist eine Anwendung, die mit Hilfe von
Application Layer Multicast Audio- bzw. Videoströme senden und empfangen kann.
Sie wurde im Rahmen einer Diplomarbeit entwickelt, um die Splitstream-Fähigkeiten
von FreePastry zu demonstrieren, Ströme aufzusplitten und über verschiedene
Routen zu versenden. Die Applikation wird als RTP Proxy ausgelegt. Das heißt sie
wird auf Netzwerkebene zwischen Streaming-Server und Mediaplayer geschaltet und
muss deshalb nicht über deren Fähigkeiten verfügen. Für die interne Kommunikation
zwischen RTP-Proxy und Streamingserver / Mediaplayer dient die lokale LoopbackSchnittstelle der Netzwerkkarte, sodass nur der RTP-Proxy außerhalb des Rechners
über das Netzwerk zu sehen ist (sh. Abb. 4-5).
Abbildung 4 - 5: Schema des P2P-Live-Video-Streaming-Proxys (Quelle:[th])
Die Anwendung ist unter Java entwickelt worden, da das Pastry API auch eine Java
Bibliothek darstellt. Das Klassendiagramm in Abbildung 4-6 zeigt die innere Struktur
von dem Programm und die möglichen Erweiterungsstellen.
- 66 -
4. Realisierung
Abbildung 4 - 6: Klassendiagramm des P2P-Live-Video-Streaming-Proxys
- 67 -
4. Realisierung
Man könnte die Klassen in drei Gruppen ordnen – Klassen für die GUI, für das
SplitStream API und für die RTP Funktionalität. Die Grafikklassen stellen eine
einfache Bedienoberfläche zur Verfügung. Die RTP Funktionalität ist dafür da, damit
beim Eintreffen von Paketen beim Empfänger, sie in der richtigen Reihenfolge an
den lokalen Mediaplayer wiedergegeben werden. Gründe dafür können starke
Laufzeitschwankungen (Jitter) sein. Diese Aufgabe übernimmt die RtpSorter Klasse,
die die eingehenden RTP Pakete nach deren RTP-Sequenz-Nummer sortiert und
gegebenenfalls bis zum Eintreffen der Vorgänger RTP Pakete zwischenspeichert.
Die wichtigen Klassen hier sind die SplitStream Klassen. Der SplitStreamHandler
kümmert sich um das Erzeugen der SplitStream-Instanz und das Anmelden an dem
Pastry-Netz. Er erzeugt zwei Instanzen des RTPSplitStreamServer und des
RTPSplitStreamClient. Die erste Klasse erfüllt die Aufgabe, die vom Streaming
Server ankommenden Pakete zu empfangen und aufgesplittet über die
verschiedenen Stripes rotierend zu verschicken (sh. Listing 4-26).
public void getRtpData(byte[] data, int dataLength) {
stripes[(stripePosition++ % tripes.length)].publish(data);
}
Listing 4 – 26: Rotierendes Verschicken von Pakete
Der SplitStreamClient ist zuständig für den Datenfluss in der umgekehrten Richtung.
Er empfängt die Datenpakete, die über den Multicast Layer ankommen, und leitet sie
an den Video Player weiter.
Die drei beschriebenen Klassen werden eine weitere Rolle beim Einbinden der
Anwendung in den externen Programmen spielen, da die Steuerung des
Datenflusses über sie läuft.
4.4.2 Anbindung an den SIP Communicator
In diesem Abschnitt werden die Änderungen präsentiert, die an dem Sip
Communicator vorgenommen wurden. Dabei handelt es sich um Änderungen, die die
SIP-Signalisierung betreffen. Zugleich werden auch die Klassen zusammen mit den
Methoden vorgestellt, die eine Rolle in diesem Zusammenhang spielen.
Der Sip Communicator besitzt eine klar definierte Klassenstruktur für die
entsprechenden Aufgaben, die erfüllt werden müssen. Beispielsweise alles, was das
GUI betrifft, findet man unter net.java.sip.communicator.impl.gui.*. Die einzelnen
Plugins werden in extra Packages implementiert und man findet sie unter
net.java.sip.communicator.plugin.*. Alle Protokolle, die der Sip Communicator
implementiert (ICQ,SIP,IRC,etc.) sind unter net.java.sip.communicator.impl.protocol.*
untergebracht. Da im SIP Protokoll Änderungen vorgenommen werden mussten,
wurden auch einige Klassen in protocol.sip Package bearbeitet.
Eine der wichtigsten Klassen hier ist die OperationSetBasicTelephonySipImpl
Klasse. Sie implementiert die komplette Logik zur Anrufsteuerung des SIP Protokolls.
In dieser Klasse findet man Methoden wie createInviteRequest(), prcocessInvite()
oder sayBye() usw., die eine INVITE-Nachricht schicken und entgegennehmen oder
ein Telefonat beenden.
- 68 -
4. Realisierung
Wie schon in den früheren Kapiteln beschrieben wurde, werden für diese Arbeit
Methoden gebraucht, die ein erneutes Senden einer INVITE–Nachricht (re-INVITE)
im Rahmen einer bereits existierenden Session ermöglichen. Die Methoden, die
diese Aufgabe erfüllen sollen, sind in Abbildung 4-6 gezeigt.
Abbildung 4 - 7: Ablauf beim Senden von re-INVITEs
Wie man erahnt, sendet die createReInvite() – Methode erneut eine INVITE
Nachricht. Angekommen beim Empfänger löst sie den Aufruf der ProcessReInvite()Methode auf, welche mit einem OK die Einladung bestätigt.
Andere wichtige Methoden in dieser Klasse sind:
•
public void startAllReInvites():Es werden an alle Konferenz-Teilnehmer ReINVITEs geschickt
•
public synchronized void createReCall(CallParticipantSipImpl c): Die Methode
erzeugt und verschickt die erneute Einladung.
•
public void processRequest(RequestEvent requestEvent): Eine der
wichtigsten Methoden. Wird immer dann aufgerufen, wenn eine Anfrage
ankommt. Es wird geschaut, was für eine Anfrage angekommen ist und
entsprechend reagiert (sh. Listing 4-27).
if (request.getMethod().equals(Request.INVITE)) { ... }
else if (request.getMethod().equals(Request.ACK)) { .. }
else if (request.getMethod().equals(Request.BYE)) { .. }
usw.
Listing 4 – 27: Abfangen der ankommenden Anfragen
- 69 -
4. Realisierung
Im Falle von einem INVITE wird überprüft, ob ein Dialog mit dem Benutzer bereits
existiert.
if (serverTransaction.getDialog().getState() == null)
Falls nicht, dann wird die Anfrage als eine Einladung zum Telefonieren interpretiert.
Ansonsten handelt es sich um eine re-INVITE Nachricht. Die Funktion wurde hier
erweitert, um festzustellen, ob in dem SDP Teil der Message eine SplitStream
Anfrage existiert (sh. Listing 4-28).
String rawRequest=new String(request.getRawContent());
String boostrapIP=rawRequest.
split("bootstrap:")[1].split("sts://")[1];
Listing 4 – 28: Herauslesen der Bootstrap IP-Adresse
Ist das der Fall, dann wird ein SplitStream Client erzeugt, welcher den P2P-LiveVideo-Streaming-Proxy repräsentiert.
•
public void processResponse(ResponseEvent responseEvent): Dies ist die
Methode, die immer aufgerufen wird, wenn der Client eine Antwort einer
vorher gesendeten Nachricht bekommt.
Je nach Response-Art wird die entsprechende Funktion aufgerufen. Für uns
interessant ist die OK-Antwort. Es wird unterschieden, ob sie aus einer INVITE oder
BYE – Nachricht stammt. War der Request eine Einladung, dann wird die
processInviteOK() Methode aufgerufen (sh. Listing 4-29).
if (response.getStatusCode() == Response.OK)
if(method.equals(Request.INVITE))
{
processInviteOK(clientTransaction,response);
}
else if (method.equals(Request.BYE))
{
//ignore
}
Listing 4 – 29: Antworten auf eine OK-Bestätigung
Die restlichen Methoden dieser Klasse werden hier nicht weiter betrachtet. Um einen
tiefere Übersicht zu bekommen, empfiehlt sich ein Blick in den Quelltext zu werfen.
Die nächste Klasse, die hier eine Rolle spielt, ist CallSessionImpl. Man findet sie
unter net.java.sip.communicator.impl.media.*. Dieses Package beinhaltet alle nötigen
Funktionen, um die Audio- bzw. Videoübertragung zu ermöglichen.
- 70 -
4. Realisierung
Die Klasse CallSessipnImpl erzeugt zwei RTP Manager (einen für Video und einen
für Audio), wenn ein Anruf initialisiert wird. Da der Sip Communicator auf JMF
aufbaut, sind momentan noch keine Konferenzgespräche möglich. Da aber in dieser
Arbeit Konferenzgespräche vorausgesetzt werden, musste der Teil für die
Audio/Video Kommunikation bearbeitet werden. Anstatt JMF wurden zwei bereit
bestehenden Anwendungen integriert – Rat und Vic.
•
Robust Audio Tool (Rat) ist eine Open-Source – Anwendung, die für Audio
Konferenzen und Streamen übers Internet eingesetzt wird. Sie läuft sowohl
unter verschiedenen Linux Derivaten als auch unter Windows. Rat basiert auf
IETF Standards und benutzt RTP über UDP/IP als Transportprotokoll. Das
Tool kann entweder im Point-To-Point Kommunikation oder im IP MulticastModus eingesetzt werden. Für das zweite wird vorausgesetzt, dass sich alle
Clients in einem Multicast – fähigen Netzwerk befinden.
•
Video Conferencing Tool (Vic) ist eine Echtzeit Anwendung für
Videokonferenzen übers Internet, welche von der „Network Research Group“
am „Lawrence Berkeley National Laboratory“ in Zusammenarbeit mit der
„University of California, Berkeley“ entwickelt worden ist. Vic ist mit einer
flexiblen und erweiterbaren Architektur konzipiert, um heterogene
Umgebungen unterstützen zu können. Das Tool setzt auch auf das RTP
Protokoll auf und für die Konferenz benötigt es eine IP Multicast – fähige
Umgebung.
Um den Sip Communicator konferenzfähig zu machen, wurden die beiden Tools
anstelle von JMF eingebaut. Wenn man die Klasse CallSessionImpl betrachtet, findet
man die Methoden startstreaming() und stopstreaming(). Sie sind verantwortlich für
das Starten bzw. Stoppen der Audio und Videoübertragung (sh. Listing 4-30). An
dieser Stelle wurden die bisherigen RTP Manager mit den zwei Tools ersetzt.
Runtime.getRuntime().exec(RATPlayerPath+ " 224.5.6.7/8910");
Runtime.getRuntime().exec(VICPlayerPath+ " 224.1.1.1/9999");
Listing 4 – 30: Starten von VIC und RAT
Wie man sieht, wird für die Anwendung einfach ein extra Prozess gestartet. Es wird
eine Multicast-IP vergeben, die frei wählbar ist. Wichtig ist, dass die restlichen Clients
die gleiche IP Adresse aufrufen. Sie müssen entsprechend in dem gleichen Netz
sein.
Eine weitere wichtige Klasse ist die CallManager Klasse. Sie beinhaltet zwei Buttons
– „Call“ und „Hangup“ auf dem Frontend Panel des GUIs. Damit werden auch die
eingehenden und ausgehenden Telefonate bedient. Das Button-Panel wurde um
noch einen Knopf erweitert, welcher für den Start einer Konferenz durch die Nutzer
benötigt wird. Das Hinzufügen eines neuen Buttons geschieht erstmal in der Klasse
ImageLoader. Dort werden die Buttons geladen und mit einer festen ImageID
versehen (sh. Listing 4-31).
- 71 -
4. Realisierung
//Button zum Hinzufügen von Konferenzgespräch.
public static final ImageID BUTTON_CONFERENCE
= new ImageID("BUTTON_CONFERENCE");
//Button zum Hinzufügen von Konferenzgespräch.
public static final ImageID BUTTON_CONFERENCE_ROLLOVER
= new ImageID("BUTTON_CONFERENCE_ROLLOVER");
public static final ImageID BUTTON_CONFERENCE_PRESSED
= new ImageID("BUTTON_CONFERENCE_PRESSED");
Listing 4 – 31: Festlegen der Icons eines Buttons
In der Datei images.properties befinden sich die Pfade aller Buttons.
Die wichtigste Methode in der Klasse CallManager ist actionPerformed(). Sie wird
immer dann aufgerufen, wenn ein Button gedrückt wurde.
Für unsere Konferenzerweiterung wurde auch eine Teilnehmer-Maske erstellt,
welche die nötigen Operationen für den Konferenzaufbau und die Erzeugung des
SplitStream – Client beinhaltet. Wenn man einen Benutzer zu einer Konferenz
einladen möchte, dann muss man ihn zuerst zu der Konferenz hinzufügen. Dies
geschieht, indem man den User selektiert und mit dem neuen Button in die
Teilnehmer – Maske hinzufügt (sh. Abb. 4-8).
Teilnehmer t = Teilnehmer.getInstance();
t.setVisible(true);
t.addContact(contact);
t.setTelephony(
mainFrame.getTelephonyOpSet(selectedCallProvider));
Listing 4 – 32: Hinzufügen von Nutzern zu einer Konferenz
Die Methode addContact() in der Teilnehmer Klasse sammelt alle eingefügten
Benutzer in einem Vector, an welchen die INVITE Nachrichten verschickt werden
sollen (sh. Listing 4-32). Zusätzlich hat man die Möglichkeit, die Pfade der externen
Tools (Vic, Rat, Vlc) einzustellen und die zu streamende Videodatei auszuwählen.
- 72 -
4. Realisierung
Abbildung 4 - 8: Starten einer Konferenz
Das Senden von INVITE und später re-INVITE Nachrichten geschieht in einem extra
Thread, um die Arbeit mit dem Programm GUI nicht zu beeinträchtigen. Ist ein
Konferenzgespräch schon aufgebaut, kann man seinen SplitStream Client starten
und den anderen Teilnehmern die Aufforderung schicken, sich in dem Pastry-Netz
anzumelden (sh. Listing 4-33).
SSImpl= new SplitStreamImpl();
SSImpl.createSplitStreamClient();
SSImpl.StartSSClient(null, "7200");
Listing 4 – 33: Starten des SplitStream Client
Die SplitStreamImpl Klasse ist die Implementierung des P2P-Live-Video-StreamingProxys.
Die in diesem Kapitel vorgestellten Klassen sind nur ein kleiner Ausschnitt aus dem
kompletten Quelltext. Sie sind aber diejenigen, die angepasst werden mussten, um
unsere Anforderungen zu erfüllen. Möchte man seine eigenen Änderungen machen,
empfiehlt sich, dass man sich an der Developer Mailing List des SIP Communicators
anmeldet und dort seine Fragen stellt.
- 73 -
5. Zusammenfassung
5. Zusammenfassung
5.1 Ergebnisse
In dieser Arbeit wurde zunächst ein Verfahren für die SIP-Signalisierung entwickelt,
das für den Aufbau von Konferenzen eingesetzt werden kann. Anschließend wird
durch das Senden von re-INVITE Nachrichten aus dem SIP Protokoll heraus eine
externe Anwendung aufgerufen. Es lassen sich beliebige Anwendungen ansteuern
und man ist frei, Startargumente zu übergeben, wie z.B. die Bootstrap-IP-Adresse
eines P2P-Netzes.
Als Nächstes wurde der SIP Communicator als Open Source Produkt präsentiert,
welches sehr geeignet für die Integration von neuen IM-Protokollen ist. Seine
modulare Struktur basierend auf der OSGi Service Plattform macht ihn besonders
geeignet, um eigene Module zu testen. Das OSGi Framework wird immer populärer
und stillt den Durst nach SOA für die Java-Entwicklung.
Mit steigender Videoqualität steigt entsprechend auch die Datenmenge, die über das
Netz übertragen werden muss. Mit dem herkömmlichen Client/Server-Prinzip wird es
für den Server zu einer enormen Belastung, alle Clients zu bedienen, im Hinblick auf
Ressourcen und die damit verbundenen Kosten. SplitStream schließt genau diese
Lücke. Die Serverlast wird auf die Peers übertragen und zusätzlich wird die
verfügbare Uploadgeschwindigkeit der Nutzer beachtet. Den Peers steht eine
kooperative Umgebung zur Verfügung, mit Rücksicht auf ihre individuellen
Fähigkeiten.
Das Integrieren des SplitStream Clients in den SIP Communicator stellt ein neues
Feature dar, das es in dieser Variante unter den bekanntesten Instant Messengern
noch nicht gibt. Damit werden die Fähigkeiten der P2P Netze auch für die IM Clients
erschlossen. Es sind auch andere Dienste als Videostreaming denkbar, wie etwa
Newsticker oder Social Networks.
Zusammenfassend kann man sagen, dass die P2P Netze eine interessante und
praktische Architektur bieten. Inzwischen kann man alle Internet-Anwendungen auch
in P2P-Netzen realisieren.
5.1 Weiterführende Aufgaben
Als eine neue und wenig entwickelte Umgebung funktioniert SplitStream nicht
reibungslos. Entwickelt man eine Applikation, so muss man selbst entscheiden, wie
die Inhalte kodiert und in Streifen geschnitten werden. Dabei muss man auch
beachten, dass jeder Streifen ungefähr dieselbe Bandbreite bekommt. Man muss
auch selbst einen Mechanismus entwickeln, um die zwischenzeitlichen Verluste von
Streifen zu tolerieren. Die vorgeschlagenen Multiple Description Coding (MDC) oder
Erasure – Codes müssen entsprechend in der Anwendung implementiert werden.
- 74 -
5. Zusammenfassung
Ein weiterer Punkt ist die Sicherheit. Es sind wenig konkrete Maßnahmen
implementiert, die eine zufriedenstellende Sicherheit bieten. Es bestehen viele
Angriffsszenarien, um das Netz zu stören, beginnend mit Man-In-The-Middle-Attack
bis Join/Leave – Flooding.
SplitStream wird weiterentwickelt und mit den neueren Versionen werden bestimmte
Aufgaben wahrscheinlich schon in der Technologie implementiert sein, damit der
Entwickler entlastet wird.
Gleichgültig mit welchen Algorithmen und Technologien, das Internet wird in den
kommenden Jahren mit Sicherheit vom Videosharing geprägt. Da die VideosharingDienste nicht nur Videos zum individuellen Anschauen bieten sollen, sondern auch
Treffpunkte für Interessensgruppen, können mit Sicherheit viele neue
Geschäftsmodelle entstehen.
- 75 -
Anhang A
Anhang A
Use Case für Integration von SplitStream mit SIP
This example describes a possible usage of the SDP Protocol to switch between SIP
and another protocol. In our case we have a SIP User Agent(UA) who is going to
invite his chat friends in a conferencing call. At some point he wishes to show a video
to his friends (for example a holiday video). The specific aspect is that this video will
be streamed in several stripes in p2p mode using splitstream. This means that we
are using an external application that establishes the p2p connections. We only want
the conferencing users to be able to see this video.
So it must be possible to switch from the SIP session to the external application that
is responsible for the handling of the connections. This draft explains our thoughts to
use the SDP header of a SIP (re-)Invite message to transmit information about how
to join to the ring of users (bootstraping).
%%%%%%%%%
%PART 1
%
%%%%%%%%%
At first Bob creates a conferencing call. He uses the "isfocus"-tag (rfc4579) in his
INVITE message to invite all participants to the conference. Alice answers with 200
OK and sets the option "Supported:conf" in the message header. The same INVITE
messages are sent to all participants. After all participiants were invited the
conferencing can start.
The figure shows how Alice and Bob have established the session.
Call-ID: [email protected]
Bob
Alice
|
|
| INVITE Contact: "Bob";isfocus F1
|
|------------------------------------>|
|
180 Ringing F2
|
|<------------------------------------|
|
200 OK Supported:conf F3
|
|<------------------------------------|
|
ACK F4
|
|------------------------------------>|
|
RTP
|
|<===================================>|
|
|
- 76 -
Anhang A
The following message shows the details of the session setup.
Bob -> Alice (INVITE)
Conference Call (Bob sets isfocus-Tag)
Bob's
IP l00.100.100.101
Alice's IP l00.100.100.102
F1:
INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP l00.100.100.101:5060;branch=z9hG4bKfw19b
Max-Forwards: 70
To: Alice <sip:[email protected]>
From: Bob <sip:[email protected]>;tag=76341
Call-ID: [email protected]
CSeq: 1 INVITE
Contact: "Bob"
<sip:100.100.100.101:5060;transport=udp>;isfocus
Content-Type: application/sdp
Content-Length: 158
v=0
o=bob 2890844526 2890844526 IN IP4 100.100.100.101
s=Phone Call
c=IN IP4 100.100.100.101
t=0 0
m=audio 49170 RTP/AVP 0
a=rtpmap:0 PCMU/8000
F3:
SIP/2.0 200 OK
Via: SIP/2.0/UDP l00.100.100.102:5060;branch=z9hG4bKfw19b
To: Bob <sip:[email protected]>;tag=a53e42
From: Alice <sip:[email protected]>;tag=76341
Call-ID: [email protected]
CSeq: 1 INVITE
Contact: "Alice" <sip:[email protected]>
Supported:conf
Content-Type: application/sdp
Content-Length: 155
v=0
o=Alice 2890844528 2890844528 IN IP4 l00.100.100.102
s=Phone Call
c=IN IP4 l00.100.100.102
t=0 0
m=audio 60000 RTP/AVP 0
a=rtpmap:0 PCMU/8000
- 77 -
Anhang A
F4:
ACK sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP l00.100.100.101:5060;branch=z9hG4bK321g
Max-Forwards: 70
To: Alice <sip:[email protected]>;tag=a53e42
From: Bob <ip:[email protected]>;tag=76341
Call-ID: [email protected]
CSeq: 1 ACK
Content-Length: 0
%%%%%%%%%
%PART 2
%
%%%%%%%%%
Now Bob wants to start an external application with the other participants. This
means he must switch from SIP to another protocol. A possible way is to send reINVITEs to the participants with changed SDP header. The SIP Header would retain
the Call-Id but in the new SDP header the external application and the required
arguments will be described.
The figure drafts the re-INVITE message flow between Bob and Alice.
Call-ID: [email protected]
Bob
Alice
|
|
| re-INVITE SDP: sts-bootstrap F1
|
|------------------------------------>|
|
180 Ringing F2
|
|<------------------------------------|
| 200 OK SDP: status=starting
F3
|
|<------------------------------------|
|
ACK F4
|
|------------------------------------>|
|
Alice starts her external
p2p-application.
In the SDP header of Bob's re-INVITE message you can find the following fields:
m=<media> <port> <transport> <format-list>
The m-field contains information about the type of media session.
m=application 7200 TCP/STS 515
We use STS (Striped Session) to identify the external application that we start. 515
was freely invented and associated with the arguments needed by the application.
- 78 -
Anhang A
a=connection:new
a=control: sts://l00.100.100.101
a=fmtp:515 bootstrap: uri="sts://l00.100.100.101:7200"
The a-fields contain attributes of the external application. They describe the type of
the connection and a bootstrap IP:PORT needed by the external application.
- connection:new is an optional field and means that it could be possible to have
more than one connection to the peer. But we do not expect this case.
- control: describes the IP address of the peer
- fmtp:515 describes the bootstrap IP and PORT where the invited peers shall join.
re-INVITE:
Bob -> Alice (Striped Session)
Bob starts re-INVITEs to all session partners, with the stripe-options (sts) in the SDP
protocol for bootstrapping.
F1:
INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP l00.100.100.101:5060;branch=z9hG4bKfw19b
Max-Forwards: 70
To: Alice <sip:[email protected]>
From: Bob <sip:[email protected]>;tag=76341
Call-ID: [email protected]
CSeq: 1 INVITE
Contact: "Bob"
<sip:100.100.100.101:5060;transport=udp>;isfocus
Content-Type: application/sdp
Content-Length: 266 (z.B.)
v=0
o=bob 2890844526 2890844526 IN IP4 100.100.100.101
s=Streaming Session
i=A Streaming session declared within the session description
protocol
c=IN IP4 100.100.100.101
t=0 0
m=application 7200 TCP/STS 515
a=connection:new
a=control: sts://l00.100.100.101
a=fmtp:515 bootstrap: uri="sts://l00.100.100.101:7200"
- 79 -
Anhang A
F3:
SIP/2.0 200 OK
Via: SIP/2.0/UDP l00.100.100.102:5060;branch=z9hG4bKfw19b
To: Bob <sip:[email protected]>;tag=a53e42
From: Alice <sip:[email protected]>;tag=76341
Call-ID: [email protected]
CSeq: 1 INVITE
Contact: "Alice" <sip:[email protected]>
supported:conf
Content-Type: application/sdp
Content-Length: 155
v=0
o=Alice 2890844528 2890844528 IN IP4 l00.100.100.102
s=Phone Call
c=IN IP4 l00.100.100.102
t=0 0
m=application 7878 TCP/STS 515
a=fmtp:515 status=starting
F4:
ACK sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP l00.100.100.101:5060;branch=z9hG4bK321g
Max-Forwards: 70
To: Alice <sip:[email protected]>;tag=a53e42
From: Bob <ip:[email protected]>;tag=76341
Call-ID: [email protected]
CSeq: 1 ACK
Content-Length: 0
- 80 -
Anhang B
Anhang B
Abbildungsverzeichnis
Abbildung 2 - 1: Kommunikation über SIP ................................................................ 10
Abbildung 2 - 2: Verbindungsaufbau mit Proxy Server ............................................. 11
Abbildung 2 - 3: RTP im TCP/IP-Protokollstapel ...................................................... 13
Abbildung 2 - 4: Client/Server Verbindungsprinzip ................................................... 14
Abbildung 2 - 5: Zentralisierte P2P-Architektur......................................................... 15
Abbildung 2 - 6: Strukturierte, dezentralisirte P2P-Architektur.................................. 15
Abbildung 2 - 7: Reine P2P-Architektur .................................................................... 16
Abbildung 2 - 8: P2P Video Streaming auf Basis von Application Layer Multicast ... 19
Abbildung 2 - 9: Ausfall eines Knoten....................................................................... 20
Abbildung 2 - 10: Korrektur des Baumes nach dem Ausfall...................................... 20
Abbildung 2 - 11: Multi-tree basiertes Streaming mit zwei Sub-streams................... 21
Abbildung 2 - 12: Abfrage der Peerliste vom Tracker-Server ................................... 23
Abbildung 2 - 13: OSGi Systemschichtung............................................................... 26
Abbildung 3 - 1: Aufbau einer Ad-hoc Konferenz...................................................... 29
Abbildung 3 - 2: Blockschaltbild MD5 ....................................................................... 33
Abbildung 3 - 3: Pastry Tabellen............................................................................... 35
Abbildung 3 - 4: Pastry, Routingtabelle .................................................................... 35
Abbildung 3 - 5: Routing einer Nachricht .................................................................. 36
Abbildung 3 - 6: Scribe Aufbau ................................................................................. 38
Abbildung 3 - 7: SplitStream Baum........................................................................... 41
Abbildung 3 - 8: OSGi-Schichten.............................................................................. 41
Abbildung 3 - 9: Zustandsdiagramm eines Bundles ................................................. 44
Abbildung 4 - 1: SplitStream, einzelne Stripes.......................................................... 46
Abbildung 4 - 2: SplitStream mit zwei Stripes ........................................................... 47
Abbildung 4 - 3: Oscar GUI....................................................................................... 58
Abbildung 4 - 4: OSGi Services ................................................................................ 58
Abbildung 4 - 5: Schema des P2P-Live-Video-Streaming-Proxys ........................... 66
Abbildung 4 - 6: Klassendiagramm des P2P-Live-Video-Streaming-Proxys............. 67
Abbildung 4 - 7: Ablauf beim Senden von re-INVITEs.............................................. 69
Abbildung 4 - 8: Starten einer Konferenz.................................................................. 73
- 81 -
Anhang C
Anhang C
Listingverzeichnis
Listing 4 - 1: SplitStream Interface........................................................................... 13
Listing 4 - 2: Eigenschaften der MySplitStreamClient Klasse .................................. 49
Listing 4 - 3: Initialisieren der Variablen ................................................................... 50
Listing 4 - 4: Anhängen an einem Channel.............................................................. 51
Listing 4 - 5: Publizieren von Daten ......................................................................... 52
Listing 4 - 6: Festlegen der Zeitabstände zum Versenden....................................... 53
Listing 4 - 7: Abfangen der angekommenen Daten.................................................. 53
Listing 4 - 8: Vorbereiten der Versuchsumgebung................................................... 54
Listing 4 - 9: Erzeugen der Nodes ........................................................................... 55
Listing 4 - 10: Starten der Nodes ............................................................................. 55
Listing 4 - 11: Programmausgabe............................................................................ 56
Listing 4 - 12: Die Activator – Klasse ....................................................................... 57
Listing 4 - 13: Manifest-Datei ................................................................................... 57
Listing 4 - 14: Kompilieren eines Bundles................................................................ 58
Listing 4 - 15: Definition vom HelloService-Interface ............................................... 59
Listing 4 - 16: Implementierung des HelloService-Interfaces................................... 38
Listing 4 - 17: Definieren von star/stop – Methoden................................................. 60
Listing 4 - 18: Setzen des Export-Package-Feldes in einer Manifest-Datei ............. 60
Listing 4 - 19: Setzen des Import-Package-Feldes in einer Manifest-Datei ............. 61
Listing 4 - 20: Implementierung des Consumer-Bundles ......................................... 61
Listing 4 - 21: Manifest-Datei eines Plugins im Sip Communicator.......................... 63
Listing 4 - 22: Implementieren des BundleActivators ............................................... 64
Listing 4 - 23: Beschreibung eines Ant - Targets in der build.xml Datei .................. 65
Listing 4 - 24: Festlegung der Kompilierreihenfolge des Ant - Targets .................... 65
Listing 4 - 25: Konfigurationsdatei definiert welche Plugins gestartet werden ......... 66
Listing 4 - 26: Rotierendes Verschicken von Pakete................................................ 68
Listing 4 - 27: Abfangen der ankommenden Anfragen............................................. 69
Listing 4 - 28: Herauslesen der Bootstrap IP-Adresse ............................................. 70
Listing 4 - 29: Antworten auf eine OK-Bestätigung .................................................. 70
Listing 4 - 30: Starten von VIC und RAT.................................................................. 71
Listing 4 - 31: Festlegen der Icons eines Buttons .................................................... 72
Listing 4 - 32: Hinzufügen von Nutzern zu einer Konferenz..................................... 72
Listing 4 - 33: Starten des SplitStream Client .......................................................... 73
- 82 -
Anhang D
Anhang D
Literaturverzeichnis
[af]
Apache Felix
http://felix.apache.org
[DHT1]
Distributed Hash Tables
http://www.dbis.ethz.ch/education/ss2005/dbs_alg_05/DHT.pdf
[dp]
Diplomarbeit, Datenverteilung in Peer-To-Peer Overlay-Netzwerken
http://www.xml-und-datenbanken.de/sada/da-pohl.pdf
[fp]
Free Pastry
http://freepastry.org/
[itw]
RTP (realtime transport protocol)
http://www.itwissen.info/definition/
lexikon/realtime-transport-protocol-RTP-RTP-Protokoll.html
[Lyl]
Diplomarbeit Lyubomir Lyubenov
Security for SIP-based P2P Internet Telephony
http://www.swt.hs-mannheim.de/cms/servlet/Download?
document=1/17854929933700.pdf
[om]
Overlay-Multicast
http://www-rnks.informatik.tu-cottbus.de/content/
unrestricted/teachings/2005/WS/
SeminarP2P/ausarbeitungen/05-overlay_multicast.pdf
[os]
Oscar Tutorial
http://oscar-osgi.sourceforge.net/tutorial/index.html
[Osp]
Die OSGi Service Platform .
ISBN : 978-3-89864-457-0
Gerd Wütherich, Nils Hartmann, Bernd Kolb, Matthias Lübken.
dpunkt.verlag
[Owk]
OSGi Alliance
http://de.wikipedia.org/wiki/OSGi
[pt]
Die Übersetzung von dem Pastry-overview
http://www4.informatik.unierlangen.de/Lehre/SS02/HS_DOOS/pdf/handout-sitiholm.pdf
[r1]
Session Initiation Protocol
RFC 3261
http://www.ietf.org/rfc/rfc3261.txt
- 83 -
Anhang D
[r2]
Session Initiation Protocol
RFC 2543
http://www.ietf.org/rfc/rfc2543.txt
[r3]
Session Initiation Protocol (SIP)
Call Control - Conferencing for User Agents
RFC 4579
http://www.ietf.org/rfc/rfc4579.txt
[sip]
SIP,TCP/IP und Telekommunikationsnetze
ISBN: 3-486-27529-1
U.Trick/F.Weber
oldenburg-verlag
[sm]
Seminar-Arbeit OSGi - The Dynamic Module System for Java
http://www.gruntz.ch/courses/sem/ss07/OSGi.pdf
[sr]
“A survey on peer-to-peer video streaming systems”
http://www.springerlink.com/content/c62114g6g4863t32/
Springer Verlag New York
[ss]
SplitStream
http://freepastry.org/SplitStream/default.htm
[thr]
Masterarbeit Thorsten Kummermehr
P2P Live Video Streaming
http://www.swt.hs-mannheim.de/cms/servlet/
Download?document=1/17863270761600.pdf
[Wiki]
Wikipedia
http://de.wikipedia.org
- 84 -
Herunterladen