44
Grundlagen der Rechnerkommunikation Praktikumsbericht hotspot“ Oliver Friedrich, Mathias Jeschke, Markus Loose und Marko Pilop (ofriedri|jeschke|loose|pilop)@informatik.hu-berlin.de http://www.informatik.hu-berlin.de/~pilop WS 2004/2005 17. Februar 2005 (Revision: 1.51 ) Humboldt-Universit¨ at zu Berlin Institut f¨ ur Informatik Dozent: Siegmar Sommer

Grundlagen der Rechnerkommunikation - Support Serverpilop/RK/praktikumsbericht.pdf · Gebrauch, wie diese auch in den Hinweisen zum Praktikum vorgeschlagen werden. Die Layer 0–Schicht,

  • Upload
    vothuan

  • View
    220

  • Download
    0

Embed Size (px)

Citation preview

  • Grundlagen der Rechnerkommunikation

    Praktikumsbericht

    ”hotspot“

    Oliver Friedrich, Mathias Jeschke, Markus Loose und Marko Pilop(ofriedri|jeschke|loose|pilop)@informatik.hu-berlin.de

    http://www.informatik.hu-berlin.de/~pilop

    WS 2004/200517. Februar 2005 (Revision: 1.51 )

    Humboldt-Universität zu BerlinInstitut für Informatik

    Dozent: Siegmar Sommer

    mailto:(ofriedri|jeschke|loose|pilop)@informatik.hu-berlin.dehttp://www.informatik.hu-berlin.de/~pilop

  • Zusammenfassung

    Dies ist die Ausarbeitung des Praktikumsberichts zur Vorlesung

    ”Grundlagen der Rechnerkommunikation“ an der Humboldt-Universität zu Berlin. Siewurde von den Autoren Oliver Friedrich, Mathias Jeschke, Markus Loose und MarkoPilop verfasst, um die Lösung der Praktikumsaufgabe zu protokollieren.

    Ziel ist die Implementierung eines lauffähigen Protokollstacks, der es Teilnehmern ei-nes Netzwerkes ermöglicht, verbindungsorientiert miteinander zu kommunizieren.

    Der entworfene und implementierte Protokollstack wurde anschließend auf die Anfor-derungen der Praktikumsaufgaben getestet.

    Sollte dieser Praktikumsbericht aktualisiert werden, so kann die aktuellste Versi-on von http://www.informatik.hu-berlin.de/~pilop/RK/praktikumsbericht.pdfheruntergeladen1 werden.

    1sollte sich dieser Pfad ändern, ist über http://www.informatik.hu-berlin.de/~pilop der neue URLerreichbar

    http://www.informatik.hu-berlin.de/~pilop/RK/praktikumsbericht.pdfhttp://www.informatik.hu-berlin.de/~pilop

  • Inhaltsverzeichnis

    1. Einleitung 6

    2. Aufgabenstellung 7

    3. Überlegungen zur Herangehensweise 83.1. Vereinfachungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83.2. Aufbau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

    3.2.1. Adressierungsarten . . . . . . . . . . . . . . . . . . . . . . . . . . . 83.2.2. Komponenten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

    3.3. Implementationstechniken . . . . . . . . . . . . . . . . . . . . . . . . . . . 103.3.1. Modellierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103.3.2. Fehler– und Flusskontrolle . . . . . . . . . . . . . . . . . . . . . . . 103.3.3. Sprache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

    4. Beschreibung der Implementierung 124.1. Schichten des Protokollstacks . . . . . . . . . . . . . . . . . . . . . . . . . 12

    4.1.1. Überblick über die Schichten des Protokollstacks . . . . . . . . . . 124.1.2. Aufbau des Protokollstacks . . . . . . . . . . . . . . . . . . . . . . 134.1.3. Kommunikation über den Protokollstack . . . . . . . . . . . . . . . 13

    4.2. Protokolle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134.2.1. Layer 0: Übertragungsprotokoll . . . . . . . . . . . . . . . . . . . . 144.2.2. Layer 1: Wegewahlprotokoll . . . . . . . . . . . . . . . . . . . . . . 144.2.3. Layer 2: Verbindungsprotokoll . . . . . . . . . . . . . . . . . . . . 154.2.4. Layer 3: Applikationsprotokolle . . . . . . . . . . . . . . . . . . . . 164.2.5. gemeinsamer Protokollstack von Layer 1 bis 3 . . . . . . . . . . . . 17

    4.3. Schnittstellen zwischen den Schichten . . . . . . . . . . . . . . . . . . . . 174.3.1. ICI / PDU / IDU . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

    4.4. Einblick in die Verbindungsschicht . . . . . . . . . . . . . . . . . . . . . . 204.4.1. Verbindungsaufbau . . . . . . . . . . . . . . . . . . . . . . . . . . . 214.4.2. Verbindungsabbau . . . . . . . . . . . . . . . . . . . . . . . . . . . 214.4.3. Fluss– und Fehlerkontrolle . . . . . . . . . . . . . . . . . . . . . . . 22

    4.5. Abläufe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224.5.1. Ziel der Beispiels–Kommunikation . . . . . . . . . . . . . . . . . . 224.5.2. Hostnamen auflösen . . . . . . . . . . . . . . . . . . . . . . . . . . 224.5.3. Datei herunterladen . . . . . . . . . . . . . . . . . . . . . . . . . . 23

    4

  • 4.5.4. Fehlerfälle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234.5.5. Flusssteuerung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244.5.6. Besondere Situationen . . . . . . . . . . . . . . . . . . . . . . . . . 24

    5. Testen der Implementierung 275.1. Modifikationen am Router . . . . . . . . . . . . . . . . . . . . . . . . . . . 275.2. Vorgehensweise beim Testen . . . . . . . . . . . . . . . . . . . . . . . . . . 27

    A. Abbildungsverzeichnis 29

    B. Kommentierter Protokollausdruck eines Testlaufs 30B.1. SYN geht verloren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30B.2. ACKs und DATA gehen verloren . . . . . . . . . . . . . . . . . . . . . . . 30B.3. Paket geht kaputt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

    C. Klassenreferenz 34C.1. CommL1Router Klassenreferenz . . . . . . . . . . . . . . . . . . . . . . . 34

    C.1.1. Ausführliche Beschreibung . . . . . . . . . . . . . . . . . . . . . . . 35C.2. ConnectionState Klassenreferenz . . . . . . . . . . . . . . . . . . . . . . . 35

    C.2.1. Ausführliche Beschreibung . . . . . . . . . . . . . . . . . . . . . . . 35C.3. Hex Klassenreferenz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

    C.3.1. Ausführliche Beschreibung . . . . . . . . . . . . . . . . . . . . . . . 36C.4. Keyboard Klassenreferenz . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

    C.4.1. Dokumentation der Datenelemente . . . . . . . . . . . . . . . . . . 37C.5. L1L0IDU Klassenreferenz . . . . . . . . . . . . . . . . . . . . . . . . . . . 37C.6. L1PDU Klassenreferenz . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37C.7. L2L1IDU Klassenreferenz . . . . . . . . . . . . . . . . . . . . . . . . . . . 38C.8. L2PDU Klassenreferenz . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38C.9. L3L2IDU Klassenreferenz . . . . . . . . . . . . . . . . . . . . . . . . . . . 39C.10.Queue Klassenreferenz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

    C.10.1.Ausführliche Beschreibung . . . . . . . . . . . . . . . . . . . . . . . 40C.10.2.Dokumentation der Elementfunktionen . . . . . . . . . . . . . . . . 40

    C.11.RecvL0 Klassenreferenz . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40C.12.RecvL3 Klassenreferenz . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41C.13.SendL0 Klassenreferenz . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41C.14.ThreadL1FromL0ToL2 Klassenreferenz . . . . . . . . . . . . . . . . . . . . 42

    C.14.1.Ausführliche Beschreibung . . . . . . . . . . . . . . . . . . . . . . . 42C.15.ThreadL1Router Klassenreferenz . . . . . . . . . . . . . . . . . . . . . . . 42

    C.15.1.Ausführliche Beschreibung . . . . . . . . . . . . . . . . . . . . . . . 42C.16.ThreadL2Alert Klassenreferenz . . . . . . . . . . . . . . . . . . . . . . . . 43C.17.ThreadL2SWOut Klassenreferenz . . . . . . . . . . . . . . . . . . . . . . . 43C.18.Tools Klassenreferenz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

    C.18.1.Dokumentation der Elementfunktionen . . . . . . . . . . . . . . . . 44

    5

  • 1. Einleitung

    Dieser Praktikumsbericht geht in Kapitel 2 zuerst auf die Aufgabenstellung ein.Darüberhinaus wird in Kapitel 3 von der Aufgabenstellung abstrahiert und geeigneteVereinfachungen vorgeschlagen. Desweiteren werden der grundlegende Aufbau und diebenutzten Implementationstechniken beschrieben.

    In Kapitel 4 wird auf den konkreten Aufbau des entworfenen Protokollstacks mit sei-nen einzelnen Schichten eingegangen. Einen besonderen Schwerpunkt erhält dabei dieSchicht, die für die Gewährleistung der Verbindung zuständig ist. An einem Beispiel wirddie Kommunikation verdeutlicht und auf Besonderheiten, wie Fehler– und Flusskontrolleeingegangen.

    Im Anschluss beschäftigt sich Kapitel 5 mit Möglichkeiten, die einzelnen Features desProtokollstacks geeignet zu testen.

    Der Protokollausdruck eines Testlaufs wird im Anhang B geliefert.

    Anhang C enthält die Dokumentation der verwendeten Klassen und Methoden.

    Es wurde weitgehend versucht, durch geeignete Farbwahl semantische Zusammenhängeunterstützend darzustellen. Dadurch soll dem Leser der Überblick erleichtert werden.

    6

  • 2. Aufgabenstellung

    Das Praktikum wurde gemäß den folgenden Aufgaben von der Website1 durchgeführt:

    1. Entwickeln Sie einen paketvermittelten Protokollstack

    • erste Schicht: Wegewahl– verbindungslos

    • zweite Schicht: Transportsteuerung– verbindungsorientiert– Fehlersteuerung– Flusssteuerung

    2. Implementieren Sie auf der Basis dieses Protokollstacks folgende Dienste

    a) Auflösen von Namen in nummerische Adressen

    b) Wegewahl (Routing) auf Basis der Adressierung

    c) Transfer einer Datei von einem Server

    3. Zeigen Sie die Funktionstüchtigkeit der Transportsteuerung im Fehlerfall

    • simulieren Sie Fehlera) Datenpaket geht vom Empfänger unbemerkt verlorenb) Datenpaket geht vom Empfänger bemerkt verlorenc) Quittung geht verloren

    4. Zeigen Sie die Funktionstüchtigkeit der Flusssteuerung

    • Simulieren die Empfangsengpässe

    5. Dokumentieren Sie Ihre Arbeit

    1http://www.informatik.hu-berlin.de/~sommer/lehre/rk/ws04/pdf/0_praktikum.pdf

    7

    http://www.informatik.hu-berlin.de/~sommer/lehre/rk/ws04/pdf/0_praktikum.pdf

  • 3. Überlegungen zur Herangehensweise

    3.1. Vereinfachungen

    Um die Aufgabe zu erfüllen, machen wir von einigen Einschränkungen und AnnahmenGebrauch, wie diese auch in den Hinweisen zum Praktikum vorgeschlagen werden.

    Die Layer 0–Schicht, wie sie in Kapitel 4.1.1 näher beschrieben wird, ist als ”Draht“ an-genommen mit den Mitteln des Betriebssystems über jeweils eine UDP/IP1–Verbindungpro Richtung zwischen den Teilnehmern des Netzwerkes als gegeben angesehen.

    Dadurch gelingt eine Voll–Duplex–Verbindung zwischen den Teilnehmern, die am sinn-vollsten über Threads implementiert wird, um die Verbindung nicht zu blockieren. Aufdiese Technik wird in Kapitel 4.4.3 bei der Beschreibung der Fluss– und Fehlerkontrolleausführlicher eingegangen.

    Die maximalen Paketlängen beschränken wir, um den Protokollstack sinnvoll testenzu können.

    3.2. Aufbau

    Wie in Abbildung 3.1 zu sehen ist, sind alle Komponenten auf verschiedene Geräteverteilt. Dies soll jedoch nicht zwingend sein, sondern nur der Veranschaulichung dienen.

    3.2.1. Adressierungsarten

    Es gibt zwei verschiedene Adressierungsarten, mit denen Teilnehmer angesprochen wer-den können.

    Adressen

    In unserem Netzwerk werden die einzelnen Teilnehmer durch eindeutige Adressen iden-tifiziert. Eine gültige Adresse ist eine ganze Zahl zwischen 1 und 127.

    Namen

    Eine weitere Darstellungsform von Adressen sind die Namen der Teilnehmer. Voraus-gesetzt, diese sind ebenfalls eindeutig, können sie vom Name–Server in die zugehörige

    1User Datagram Protocol über IP

    8

  • Abbildung 3.1.: Veranschaulichung des Aufbaus der einzelnen Komponenten (Adressenin Klammern)

    Adresse umgesetzt werden. Dies ist kein Feature des Netzwerkes, sondern ein eigenständi-ger Dienst, der auf unserem Protokollstack aufsetzt. Dazu wird in Abschnitt 4.2.4 dasNamensauflösungsprotokoll erklärt.

    3.2.2. Komponenten

    Im folgenden werden die einzelnen Komponenten unseres Netzwerkes kurz vorgestellt.Vordergründig sollen dabei die Aufgaben erläutert werden. Im Kapitel 4.5 wird dasZusammenspiel der Komponenten anhand der zu bewältigenden Aufgabe2 erklärt.

    Der Client

    Der Client mit der Adresse 1 hat die Aufgabe, eine Datei vom File–Server herunterzu-laden. Dafür benötigt er zuerst die Adresse des File–Servers, die er durch eine entspre-chende Anfrage beim Name–Server aufzulösen versucht. Auf die verwendeten Protokollewird gesondert in Abschnitt 4.2.4 eingegangen.

    Der Router

    Der Router mit der Adresse 2 ist für die Wegewahl im Netzwerk zuständig. Er analysiertDatenpakete auf unterster Ebene, um sie entprechend zuzustellen. Er nimmt die zentralePosition ein, da jeder Teilnehmer im Netzwerk über ihn kommunizieren muss. Dazumuss jeder Teilnehmer seine Adresse kennen. In unserem vereinfachten Aufbau hat jederTeilnehmer fest diese Adresse gewissermaßen als Gateway eingetragen.

    2siehe Kapitel 2

    9

  • Der Name–Server

    Der Name–Server mit der Adresse 4 hat ein Verzeichnis, in dem jedem Namen eines Netz-werkteilnehmers seine Adresse zugeordnet ist. Auf eine Anfrage versucht er die passendeAdresse zurückzuliefern. Die Adresse des Name–Servers ist dem Client bekannt. Dasentsprechend einfache Namensauflösungsprotokoll wird in Abschnitt 4.2.4 beschrieben.

    Der File–Server

    Der File–Server mit der Adresse 3 stellt eine Datei bereit, die auf Anforderung, über dasin Abschnitt 4.2.4 beschriebene Dateitransferprotokoll, heruntergeladen werden kann.

    3.3. Implementationstechniken

    3.3.1. Modellierung

    In der ersten Grundlegenden programmiertechnischen Entscheidung, die zu treffen war,legten wir uns auf eine objektorientierte Modellierung fest, da diese mit ihren Abstrak-tionsansätzen hilfreich für die Wiederverwendung von Code ist.

    Um die einzelnen Protokollschichten zu implementieren und miteinander zu verbinden,kam für uns entweder eine Kapselung über eine Funktion pro Schicht und Richtungin Frage, oder eine saubere Trennung aller Schichten in einzelne Threads. Die ersteMethode wäre vergleichsweise einfach gewesen, jedoch entschieden wir uns für die klareUnterteilung, um die Schichten unabhängig voneinander zu machen.

    Dadurch wurde natürlich der Transport der Daten zwischen den Schichten etwas kom-plizierter, den wir mittels Transport–Queues lösten, die in Kapitel 4.3 näher beschriebenwerden.

    Durch die Verwendung von zwei Threads pro Ebene, ist der Datenfluss Voll–Duplexmöglich.

    3.3.2. Fehler– und Flusskontrolle

    Bei der Fehler– und Flusskontrolle setzen wir auf das kombinierte Sliding–Window–Verfahren, bei dem sich Sender und Empfänger dynamisch auf eine Fenstergröße einigenund der Sender immer nur so viele Pakete senden kann, wie er ”Kredit“ in Form vonfreiem Platz im Fenster–Puffer besitzt. Erst wenn der Empfänger das Fenster bestätigt,kann der Sender weitere Pakete schicken. Durch Anpassen der Fenstergröße an die aktu-elle Verbindungsqualität kann der Datenfluss bei guter Verbindung gesteigert, oder beischlechter gesenkt werden.

    Durch die Verwendung eines Fenster–Algorithmus, ist es nicht notwendig jedes Paketeinzeln zu bestätigen, was den Protokoll–Overhead speziell bei kleinen Datenpaketenextrem senken kann.

    In Kapitel 4.4.3 wird auf die konkrete Implementation näher eingegangen.

    10

  • 3.3.3. Sprache

    Die Sprachwahl, wohl der unwichtigste Aspekt, hielten wir uns bis zum Start der Im-plementationsphase offen. Im Vorfeld testeten wir einige Grundlegende Funktionen inverschiedenen Sprachen und legten uns dann auf Java3 fest.

    3Wir entwickelten unter Version 1.4.2 sowohl mit Blackdown–, alsauch mit Sun–Java.

    11

  • 4. Beschreibung der Implementierung

    4.1. Schichten des Protokollstacks

    Unser Protokollstack setzt sich aus mehreren Schichten zusammen. Dieser Protokollstackmuss in allen Teilnehmern des Netzwerkes gleichermaßen implementiert sein, da über ihnund die Schichten genau definiert ist, wie die Datenpakete übertragen und verarbeitetwerden. Dabei muss nicht zwangsläufig jeder Teilnehmer alle Schichten implementierthaben. Der Router zum Beispiel trifft seine Entscheidungen auf Layer 1 und muss so diedarüber liegenden Schichten nicht kennen.

    4.1.1. Überblick über die Schichten des Protokollstacks

    Im folgenden soll ein erster kurzer Überblick über die einzelnen Schichten unseres Pro-tokollstacks gegeben werden.

    Layer 0

    Layer 0 ist die unterste Schicht unseres Protokollstacks. Sie arbeitet auf der Ebene des

    ”Drahtes“, der aus den Mitteln des Betriebssystems über UDP/IP simuliert wird. DieseSchicht ist grundsätzlich verbindungslos.

    Layer 1

    Layer 1 liegt direkt über Layer 0 im Protokollstack. Diese Schicht ist für die Wegewahlzuständig. Sie sorgt dafür, dass Pakete über den Router anhand der Adresse an den rich-tigen Rechner weitergeleitet werden. Auch diese Schicht ist grundsätzlich verbindungslos.Das Protokoll ähnelt in der realen Welt am ehesten IP1.

    Layer 2

    Layer 2 liegt direkt über Layer 1 und sorgt für die Verbindung. Mittels dieser Schichtwerden Verbindungen für die Pakete aufgebaut, um eine Fehler– und Flusssteuerung zugewährleisten. In der realen Welt hat das Protokoll dieser Schicht große Ähnlichkeit mitTCP2.

    1Internet Protocol2Transmission Control Protocol

    12

  • Layer 3

    Layer 3 ist die Applikationsebene und direkt über Layer 2 angeordnet. In dieser Schichtsind die Protokolle des Name– und File–Servers beheimatet. Die weitaus komplexerenProtokolle wie DNS3 oder HTTP4 gelten in der realen Welt als Vorbild.

    4.1.2. Aufbau des Protokollstacks

    Wie eben schon im Überblick beschrieben, liegen die Schichten übereinander. Abbil-dung 4.1 stellt den gesamten Protokollstack schematisch dar.

    Abbildung 4.1.: Schematische Darstellung der Schichten des Protokollstacks

    4.1.3. Kommunikation über den Protokollstack

    Abbildung 4.2 verdeutlicht wie die Daten von der Applikationsebene des Kommunikati-onspartners A den Protokollstack von oben nach unten durchlaufen, um dann über den

    ”Draht“ zu Kommunikationspartner B übertragen zu werden. Dort wandern die Datendie Schichten hinauf, indem in jeder Ebene der Header vom Payload getrennt wird unddie Daten protokollgemäss weitergeleitet werden. Die genaueren Verfahren, mit denendie Daten zwischen den Schichten transportiert werden, sind in Abschnitt 4.3 erläutert.

    4.2. Protokolle

    In diesem Abschnitt werden die PDUs5 unseres Protokollstacks vorgestellt. Die Dimen-sionierung der einzelnen Felder im Paket sind jeweils darunter notiert. Wir verwendenausschließlich ganze Bytes6, auch um Informationen zu kodieren, die auch nur durch ein

    3DomainName–Service4HyperText–Transfer Protocol5Protocol Data Unit6mit jeweils 8 Bit

    13

  • Abbildung 4.2.: Schematische Darstellung des Protokoll–Flusses bei der Kommunikationdurch die Schichten des Protokollstacks

    Bit repräsentiert werden könnten. Mehrere Bit–Informationen, wie zum Beispiel Flags,die logisch zusammenhängen werden jedoch meist in einem Byte zusammen kodiert.

    4.2.1. Layer 0: Übertragungsprotokoll

    PAYLOAD L0

    max 108

    Das Übertragungsprotokoll bietet Platz, um sämtliche darüber liegenden Schichteneinzubetten. Die Pakete werden über den ”Draht“ zum Kommunikationspartner ver-schickt.

    4.2.2. Layer 1: Wegewahlprotokoll

    DST SRC SIZE PAYLOAD L1

    1 1 1 max 105

    Das Wegewahlprotokoll dient der Adressierung der Pakete. Um Empfänger– und Ab-senderinformationen anzugeben, sind die ersten beiden Felder vorgesehen. Im drittenFeld wird die Größe der nachstehenden Daten angegeben.

    14

  • Feld Funktion BeschreibungDST Destination Adresse des EmpfängerhostsSRC Source Adresse des AbsenderhostsSIZE Size Größe des Payloads (L1) in Bytes

    PAYLOAD L1 Payload Daten aus Layer 2

    4.2.3. Layer 2: Verbindungsprotokoll

    OPT ID ACKID WND CRC PAYLOAD L2

    1 1 1 1 1 max 100

    Feld Funktion BeschreibungOPT Options Optionen [SYN, ACK, FIN, DATA] (siehe Text)

    ID Identification Sequenznummer des PacketsACKID Acknowledge ID Größte Sequenznummer der bestätigten Pakete

    WND Window Größe des Sliding–Window (Anzahl der Pakete)CRC Checksum Prüfbit, zur Sicherung der Datenintegrität

    PAYLOAD L2 Payload Daten aus Layer 3

    Das erste Feld eines Verbindungsprotokollpakets besteht aus den Optionen, die alsfünf Flags repräsentiert werden. Dabei dient das SYN –Flag zum Verbindungsaufbau unddas FIN –Flag zum Verbindungsabbruch. Das ACK–Flag dient der Fehlersteuerung, umPakete zu bestätigen. Es spielt eine übergeordnete Rolle, da dieses allgemein zur Bestäti-gung auch beim Verbindungsaufbau und –abbruch (siehe Abschnitte 4.4.1 bzw. 4.4.2)mit verwendet wird. Das DATA–Flag signalisiert tatsächlich verwertbare Daten im Pay-load, die weitergeleitet werden müssen. Alle anderen Flags dienen Kontroll–Aufgabenund der Payload wird ignoriert7.

    Folgende Kombinationen von Flags sind gültig8:Flags BedeutungSYN der Client möchte eine Verbindung aufbauen (Handshake Teil 1)

    SYN,ACK der Server kommt der Aufforderung nach (Handshake Teil 2)ACK das Paket mit aktueller ID wird als empfangen bestätigtFIN die Verbindung soll beendet werden

    FIN,ACK die Verbindung wurde beendet (dies ist letztes Paket)DATA das aktuelle Paket enthält Daten

    DATA,ACK das aktuelle Paket enthält Daten und dient der Bestätigung (Piggy–Backing)

    Nach den Optionen folgt das ID-Feld mit der Sequenznummer des Paketes. Anschlie-ßend die ACKID, mit der die Information steht, welche Pakete bestätigt werden, falls

    7in der Regel sollte der Payload ohne DATA–Flag konsistenterweise leer sein.8Alle anderen Kombinationen von Flags sind nicht definiert und werden daher ignoriert.

    15

  • das ACK–Flag gesetzt ist. In WND ist die zur Zeit gültige Fenstergröße definiert. CRCdient als Prüfbit, dass in einer echten Implementierung eine Prüfsumme über den Pay-load gewesen wäre. Hier ist es nur der Integritätsstatus des Payloads, zeigt also direktan ob das Paket kaputt ist, oder nicht.

    4.2.4. Layer 3: Applikationsprotokolle

    PAYLOAD L3

    max 100

    Feld Funktion BeschreibungPAYLOAD L3 Payload Daten aus Layer 3

    Auf Ebene 3 basieren die zwei Hauptprotokolle. Für jeden Dienst existiert ein eigenes.Beide werden im Folgenden näher spezifiziert.

    Namensauflösungsprotokoll

    Nachdem der Client die Verbindung zum Name–Server aufgebaut hat, sendet er denNamen, der aufgelöst werden soll. Aufgrund der Beschränkung eines Namens auf 1 (!??)Zeichen, ist es möglich die Anfrage in einem Paket zu stellen.

    Der Name–Server antwortet mit der aufgelösten Adresse, was ebenfalls in einem Paketmöglich ist. Sollte die Namensauflösung scheitern, sendet der Name–Server die Adresse0 als Fehler zurück.

    Im Anschluss an diesen Vorgang beendet der Server die Verbindung.

    Dateitransferprotokoll

    Der Client baut eine Verbindung zum File–Server auf und sendet den Namen der Datei,die er herunterladen möchte. Da die Länge des Namens auf 64 (!??) Zeichen beschränktist, kann auch diese Anfrage in einem Paket übertragen werden.

    Der File–Server beginnt daraufhin mit dem Senden der Datei. Da die Datei beliebig9

    groß sein kann, müssen die Daten auf verschiedene Pakete verteilt werden. Dazu werdenalle Pakete maximal ausgelastet, d.h. mit den vollen 100 Byte Payload versehen. Dasletzte Paket, trägt eventuell weniger Daten, nämlich nur soviele, wie noch für die Dateizu übertragen sind.

    Um das Ende der Datei bekannt zu geben, beendet der Server im Anschluss die Ver-bindung.

    9nur durch Ressourcen begrenzt

    16

  • 4.2.5. gemeinsamer Protokollstack von Layer 1 bis 3

    Im folgenden ist der in sich gekapselte Protokollstack der Ebenen 0 bis 3 zu sehen:

    DST SRC SIZE OPT ID ACKID WND CRC PAYLOAD L3

    1 1 1 1 1 max 100 Bytes

    1 1 1 max 105 Bytes

    max 108 Bytes

    Die einzelnen PDUs der Protokollschichten sind ineinander eingebettet. Dadurch wirdauch klar, wie die maximal mögliche Gesamtgröße eines Paketes auf Übertragungsebenezustande kommt.

    4.3. Schnittstellen zwischen den Schichten

    Da wir uns entschlossen haben, die einzelnen Schichten jeweils in zwei Threads zu imple-mentieren, stellt sich nun die Frage, wie diese die Daten austauschen. Für diese Übergabedes Payloads einer Schicht an die nächste haben wir Transport–Queues eingeführt. Da-durch ist es möglich, diese Warteschlangen für die Daten als Puffer zu benutzen, so dassdie Threads zeitlich nicht so sehr von einander abhängig sind.

    Neben dem Transport der eigentlichen Pakete als PDU–Strukturen, ist es teilweisenotwendig zusätzliche Steuerinformationen an die darunterliegende Schicht zu übermit-teln, die nicht aus dem Paket entnommen werden können, da die untere Schicht nichtdie Daten der oberen Schicht versteht. Diese ICIs werden zusammen mit den PDUsübertragen und sind in Abschnitt 4.3.1 erklärt.

    Es sind, wie in Abbildung 4.3 zu sehen ist, immer zwei direkt benachbarte Schichtenüber die Transport–Queues verbunden.

    Dabei dient jeweils eine Queue dazu, um die Daten eine Schicht nach unten zu leitenund die andere, um sie eine Schicht nach oben weiterzureichen.

    In der exemplarischen Ausschnittvergrößerung von Abbildung 4.3 sind die beidenTransport–Queues zwischen der Applikationsebene und der Verbindungsebene darge-stellt. Offensichtlich dient L2-L3 dem Transport vom Layer 2 zum Layer 3, währendL3-L2 für die umgedrehte Reihenfolge zuständig ist.

    4.3.1. ICI / PDU / IDU

    Zwischen den Schichten werden nicht nur die Datenpakete übertragen. Besonders fürdie Kommunikation zu unterliegenden Schichten ist es wichtig, weitere Daten zu über-mitteln. Die bisher in Abschnitt 4.2 besprochenen PDUs werden zusammen mit der

    17

  • Abbildung 4.3.: Schematische Darstellung der Kommunikation zwischen den Schichtenmittels Transport–Queues.

    Interface Controll Information (ICI) in eine Interface Data Unit (IDU) ge-packt. Zum Beispiel muss Layer 3 die Adresse des Zielrechners mit an Layer 2 übergeben.Dazu wird einfach die ICI mit dem zu sendenden Paket (PDU) in ein Objekt gehülltund über die entsprechende Transport–Queue übertragen. In diesem Anschnitt sind dievorkommenden IDUs dargestellt, die jeweils ICI und PDU enthalten.

    Layer 3 ↔ Layer 2

    Zwischen der Applikationsebene und der Verbindungsebene müssen Informationen kom-muniziert werden, die

    1. von Layer 3 einen Verbindungswunsch an Layer 2 einer ausgehenden Verbindung

    2. von Layer 2 einen Verbindungswunsch an Layer 3 einer eingehenden Verbindung

    3. von Layer 3 den Verbindungsabbau an Layer 2

    4. von Layer 2 den Verbindungsabbruch an Layer 3

    übermitteln.

    18

  • Soll eine Verbindung initiiert werden, so muss der Verbindungsebene außerdem nochdie Adresse des Kommunikationspartners mitgeteilt werden. Die dafür verwendete IDUist nachfolgend zu sehen:

    PDU Layer 3 ADR OPT

    max 100 1 1

    Dabei ist ADR je nach Richtung die Absender10– oder Empfängeradresse11 und OPTsind die möglichen Optionen mit folgenden Flags:

    Flags BedeutungNEW der Client möchte eine Verbindung aufbauen (Handshake Teil 1)END die Verbindung soll beendet werdenEST Verbindung hergestelltERR Verbindungsaufbau schlug fehl

    Die letzten beiden Flags (EST und ERR) werden ausschließlich von Layer 2 nachLayer 3 benutzt. Die anderen Flags können bei beiden Richtungen auftreten.

    Layer 2 ↔ Layer 1

    Von der Verbindungsebene zur Wegewahl muss zusätzlich die Informationen übertragenwerden, zu welcher Zielhost–Adresse die Verbindung besteht, damit sie in Layer 1 ein-getragen werden kann. Die Quell–Adresse ist dieser Schicht automatisch bekannt, da sieeinkonfiguriert ist. Umgekehrt muss die Absenderadresse aber von Layer 1 nach Layer 2übertragen werden. Diese zusätzlichen Adressangaben finden sich im ADR–Feld.

    Die entsprechende IDU sieht folgendermaßen aus:

    PDU Layer 2 ADR

    max 105 1

    Layer 1 ↔ Layer 0

    Da auf der Schicht der Wegewahl die Routing–Entscheidung getroffen wird, muss an dieÜbertragungsebene der ”Zieldraht“ in Form des UDP–Ports angegeben werden. Für alleTeilnehmer ist das der Port des Routers. Der Router selbst wählt anhand seiner Tabelle.

    Die entsprechende IDU sieht so aus:

    PDU Layer 1 UDP–Port

    max 108 4

    10Layer 2 → Layer 311Layer 3 → Layer 2

    19

  • 4.4. Einblick in die Verbindungsschicht

    Da die gesamte Intelligenz der Verbindung in Layer 2 implementiert ist, fällt diese Schichtetwas komplexer aus, als die anderen.

    Zur Veranschaulichung ist in Abbildung 4.4 ein Einblick in die Verbindungsebenegegeben. Über vier Transport–Queues sind die zwei Threads SlidingWindowOut undSlidingWindowIn an die angrenzenden Schichten angebunden.

    Abbildung 4.4.: Interner Aufbau von Layer 2 mit den zwei Threads.

    In Abschnitt 4.4.3 wird näher auf das verwendete Sliding–Window–Verfahren einge-ganden. Dort sind auch zu jedem der beiden Threads entsprechende Fluss–Diagramme12

    abgebildet, die das Zusammenspiel verdeutlichen.

    12siehe Abbildungen 4.5 und 4.6

    20

  • 4.4.1. Verbindungsaufbau

    Um eine Verbindung aufzubauen, wird auf der Applikationsebene der Verbindungsaufbauüber eine NEW –IDU initiert. Zusätzlich muss der Client noch die Adresse des Serversangeben, zudem er verbunden werden möchte.

    Diese Daten gelangen dann in Form einer IDU über eine Transport–Queue zur Verbin-dungsebene. Dort wird zunächst mittels der ConnectionState[0]–Variablen überprüft,ob schon eine Verbindung besteht. Ist dies der Fall, wird direkt der Fehlschlag des Verbin-dungsaufbaus über die andere Transport–Queue zurück zur Applikationsebene mittelseiner IDU übermittelt.

    Sollte jedoch noch keine Verbindung bestehen (getConnState() == 0), so wird ver-sucht, sie aufzubauen. Dies geschieht, indem ein Paket mit gesetzem SYN –Flag im OPT–Feld über die Transport–Queue zu Layer 1 geschickt wird. Dazu gehört auch wieder dieICI–Information des Zielhosts, die ja von Layer 3 mit übergeben wurden. Zusätzlich wirdin der Variablen ConnectionState[1] (Zieladresse) vermerkt, dass der Verbindungsauf-bau gerade im Gange ist.

    Layer 1 verarbeitet die Daten weiter und fügt Ziel– und Absenderadresse dazu. Letzte-re ist bekannt, da jeder Teilnehmer seine eigene Adresse kennt. Nun wird noch die Größeder eingebetteten Daten der überliegenden Schichten in das SIZE–Feld eingetragen undüber die Transport–Queue zur Übertragungsschicht weitergeleitet.

    Diese sendet das Paket über den ”Draht“ zum Router, der das Paket auf Wegewahle-bene analysiert und entsprechend seiner Tabelle an die Zieladresse weiterleitet.

    Beim Server wandert das Paket wieder den Protokollstack bis zur Verbindungsebenehoch. Dort wird aufgrund des darin gesetzten SYN –Flags der Verbindungsaufbauhand-shake erwidert. Besteht noch keine Verbindung, d.h. getConnState() == 0, so wird einAntwortpaket generiert, in dem die gleiche ID verwendet wird, der Payload leer ist unddie Flags SYN und ACK im OPT–Feld gesetzt sind. Nun wird auch auf Serverseitein der Variablen ConnectionState[1] vermerkt, dass die Verbindung im Aufbau ist.Besteht schon eine Verbindung, wird das Paket verworfen.

    Geht eines der beiden Pakete auf dem Weg zum Kommunikationspartner verloren, sowird es nach einem Timeout erneut versandt, wenn keine protokollgemäße Antwort kam.

    Hat es das SYN,ACK–Paket jedoch bis zum Client zurückgeschafft, wird inConnectionState[1] die Adresse seines Absenders eingetragen. Zur Applikationsebenewird die IDU geschickt (mit Options == EST in der ICI), dass die Verbindung nun bereitist.

    Jetzt kann die Applikation Daten über die Verbindung versenden. Mit dem Eintreffendes ersten Datenpakets beim Server, vermerkt auch dieser die Verbindung als Aktiv,indem er die Client–Adresse in ConnectionState[1] einträgt.

    4.4.2. Verbindungsabbau

    Eine bestehende Verbindung kann von jedem der beiden Komminikationspartner zu je-der Zeit beendet werden. Dazu sendet er ein Paket mit gesetzem FIN –Flag. Antwortetder Partner mit einem FIN,ACK–Paket, so ist die Verbindung beendet und in beiden

    21

  • Teilnehmern ConnectionState[0] == 0.

    4.4.3. Fluss– und Fehlerkontrolle

    Wie bereits bei den Vorüberlegungen erwähnt, haben wir für die Flusssteuerung undFehlerkontrolle den Sliding–Window–Algorithmus benutzt. Die Fluss–Diagramme desimplementierten Algorithmus sind in den Abbildungen 4.5 und 4.6 zu sehen.

    Nach dem erfolgreichen Verbindungsaufbau sind beide Kommunikationsteilnehmer be-reit, Daten über die geschaffene Verbindung auszutauschen. Dies geschieht folgenderma-ßen: Der Sender nimmt zuerst Pakete von Layer 3 an und speichert diese im Sendefenster,bis dieses voll ist. Anschließend sendet er die Fensterelemente sequentiell über den Pro-tokollstack zum Empfänger. Jedem Paket wird eine Sequenznummer zugeordnet, dienach jedem Datenpaket inkrementiert wird. Der Empfänger prüft, ob die eingehendenSequenznummern schon in seinem Fenster sind. Ist dies so, hat er bereits die Paketeerhalten und kann die Duplikate verwerfen. Ansonsten speichert er die eingetroffenenPakete im Empfangsfenster an die entsprechende Position13. Ist die obere Schranke desEmpfangsfensters, die gleich der relativen Größe des Sendefensters + untere Schranke ist,dann werden die empfangenen Pakete aus dem Empfangsfenster an Layer 3 weitergeleitetund ein ACK–Paket14 an den Sender über Layer 1 geschickt.

    Währendessen wartet der Sender eine Zeit lang (Timeout = 2·Roundtrip–Zeit) auf dasACK–Paket. Sollte die Quittung in dieser Zeit nicht eintreffen, wird das Sendefenstererneut gesendet.

    Sonst wird das Sendefenster gelöscht und es können neue Daten vom Sender aus derApplikationsebene entgegengenommen werden. Dieses Verfahren wird für die gesamteKommunikation fortgeführt.

    4.5. Abläufe

    Dieser Abschnitt versucht die konkreten Abläufe anhand einer Beispiel–Kommunikationzu erklären. Dabei werden einige zentrale Schlüsselmechanismen untersucht.

    4.5.1. Ziel der Beispiels–Kommunikation

    Die Beispiel–Kommunikation soll die Prozesse beschreiben, die notwendig sind, um diePraktikumsaufgabe zu lösen: Eine Datei soll von einem File–Server heruntergeladen wer-den.

    4.5.2. Hostnamen auflösen

    Dazu benötigt der Client als erstes die Adresse des File–Servers. Diese kennt er nochnicht. Er kennt lediglich die Adresse des Name–Servers, den er fragen kann.

    13bezüglich der Sequenznummer und der unteren Schranke: Pos = SeqNo - untere Schranke14mit ACKID = höchste Sequenznummer + 1

    22

  • Verbindungsaufbau

    Der Client muss also die Verbindung mit dem Name–Server initialisieren. Dies geschiehtdurch eine NEW –IDU. Während sich Layer 2 um den Verbindungsaufbau kümmert,muss die Applikation auf Layer 2 nur warten, bis sie die Nachricht der aufgebautenVerbindung bekommt. Im Fehlerfall bekommt sie eine entsprechende Negativ–Nachricht.Gründe dafür könnten zum Beispiel sein, dass Paketverluste den Verbindungsaufbauscheitern ließen, oder der Server gerade beschäftigt ist. Eine schlechte Ursache wäre,wenn die Adresse des Name–Servers falsch ist.

    Eigentliche Kommunikation

    Ist die Verbindung aufgebaut, kann der Client entsprechend des Namensauflösungspro-tokolls (siehe Abschnitt 4.2.4) den aufzulösenden Hostnamen senden. Als Antwort be-kommt er die Adresse zurück. Ist diese Adresse 0, so konnte die Anfrage nicht aufgelöstwerden.

    Verbindungsabbau

    Mit seiner Antwort hat der Server automatisch den Verbindungsabbruch veranlasst. DerClient bekommt dies auf Applikationsebene über eine Nachricht mitgeteilt.

    4.5.3. Datei herunterladen

    Damit ist der Client nun in Besitz der Adresse des File–Servers. Nun kann er im zweitenSchritt analog zur eben geschilderten Prozedur die Verbindung dorthin aufbauen. Dannkann er über das Dateitransferprotokoll (siehe Abschnitt 4.2.4) die gewünschte Dateianfordern und erhält sie daraufhin vom Server. Da die Datei unter Umständen groß seinkann, wird sie in vielen Paketen übertragen.

    Ist die Datei übertragen, beendet der Server die Verbindung.

    4.5.4. Fehlerfälle

    Bei der Übertragung der Pakete über den ”Draht“ können verschiedene Fehler auftreten,die durch erneutes Senden der Daten korrigiert werden. In Abschnitt 5.2 wird ausserdemdarauf eingegangen, wie diese Fehlerfälle simuliert werden können.

    Ein Paket geht bemerkt verloren

    Eigentlich geht das Paket dabei nicht wirklich verloren, es ist nur irgendwie kaputtgegangen. Dies kann die Verbindungsschicht des Empfängers über das CRC–Feld her-ausfinden. Dadurch das der Empfänger das kaputte Paket nicht bestätigt, wird es vomSender nach einem Timeout erneut gesendet.

    23

  • Ein Paket geht unbemerkt verloren

    Ein Paket geht unbemerkt verloren, wenn es beim Empfänger nicht ankommt, da diesernichts von dem Paket weiß. Da er es daher nicht bestätigen kann, muss der Sender esnach einem Timeout erneut übertragen.

    Eine Quittung geht verloren

    Nun gibt es noch den Fall, dass ein ACK–Paket verloren geht. Dies wird ebenso kor-rigiert, indem der Sender keine Bestätigung bekommt und das Datenpaket nocheinmalsendet. Der Empfänger bekommt so das Paket zwar zweimal, bemerkt es aber aufgrundder Sequenznummer und kann die Quittung erneut senden.

    4.5.5. Flusssteuerung

    Stellt der Sender eine schlechte Verbindung fest, kann er die Fenstergröße des Sliding–Window anpassen. Dies erkennt er anhand der verlorengegangenen Pakete, die er erneutsenden muss. Solange aber keine Pakete verloren gehen, vergrößert er die Fenstergrößestetig, bis zum Maximum. Zu Beginn einer Verbindung ist die Fenstergröße mit 1 in-itialisiert, d.h. es kann genau ein Paket gesendet werden. Erst nachdem es über eineQuittung bestätigt wurde, darf weitergesendet werden.

    4.5.6. Besondere Situationen

    Damit die Transport–Queues nicht den Empfang von wichtigen Verwaltungspaketen, wiezum Beispiel den Quittungen verstopfen, werden diese auf das doppelte der maximalenFenstergröße dimensioniert. Sonst würde der Sliding–Window–Algorithmus sich selbstblockieren, wenn das Sliding–Window voll ist und keine Quittungen durchkommen, dieden Algorithmus weiterlaufen lassen.

    Da der Vorrat an Sequenznummern sehr beschränkt ist, werden möglicherweise imLaufe einer Verbindung Sequenznummern mehrfach verwendet. Dieses Phänomen wirdzyklisch auftreten und bei größeren Daten, wie zum Beipiel dem Dateitransfer zu beob-achten sein.

    Damit daraus keine negativen Auswirkungen auf den Sliding–Window–Algorithmusresultieren, haben wir die maximale Fenstergröße auf kleiner als die Hälfte der höchstenSequenznummer begrenzt. Dadurch ist es möglich Sequenznummern, die an der Byte–Grenze überlaufen sicher zu erkennen und korrekt zuzuordnen.

    24

  • Abbildung 4.5.: Fluss–Diagramm des implementierten Sliding–Window–Algorithmus imSender (ThreadL2SWOut).

    25

  • Abbildung 4.6.: Fluss–Diagramm des implementierten Sliding–Window–Algorithmus imEmpfänger (ThreadL2SWIn).

    26

  • 5. Testen der Implementierung

    Um die Implementierung zu testen, ist es wichtig, den gesamten Netzwerkverkehr beob-achten zu können. Zwar ist es prinzipiell möglich, jede Station selbst loggen zu lassen unddiese Daten zu verbinden, jedoch ist dies sehr aufwändig und erfordert im ungünstigstenFall weitere Netzwerkkommunikation.

    Ein anderer Ansatz, den wir verfolgen, ist es einfach den Router zu ”belauschen“.Da der Router in seiner zentralen Position im Netzwerk jedes Paket ”sieht“, ist es aufeinfache Weise möglich, diese sogar in chronologischer Reihenfolge zu loggen.

    5.1. Modifikationen am Router

    Natürlich wollen wir nicht nur zusehen, sondern auch aktiv eingreifen. Dafür bieten wirdie Möglichkeit, die Kommunikation

    1. zu verlangsamen1

    2. zu manipulieren

    a) Pakete zerstören2

    b) Pakete verlieren

    c) Bandbreite begrenzen

    Eine Verlangsamung der gesamten Kommunikation ist nur auf dem Router nichtmöglich, da durch eine Verzögerung irgendwann die Timeouts der verschiedenen Schich-ten nicht mehr funktionieren. Es kann daher nur in Maßen verzögert werden.

    Da der Router prinzipbedingt nur die Layer 0 und Layer 1 kennt, um seine Aufgabe zuerfüllen, gaben wir ihm zusätzlich Methoden zum Dekodieren der Verbindungsschicht,damit die Log–Ausgaben lesbarer sind.

    5.2. Vorgehensweise beim Testen

    Zuerst ist natürlich die ungestörte Kommunikation interessant. Daran kann man Verbindungsauf–und abbau erkennen.

    Danach geht es darum Pakete gezielt zu zerstören, indem die Prüfsummeninformationin den Layer 2–Paketen manipuliert wird. Durch diese Maßnahme sollte ein kaputtes

    1um besser zusehen zu können2d.h. das Prüfbit verändern, sodass das Paket vom Empfänger abgewiesen wird

    27

  • Paket vom Empfänger verworfen werden. Daher erhält der Sender kein ACK–Paket undsendet nach einem Timeout das Paket nochmal.

    Desweiteren können wir ausgewählte Pakete auf dem Router einfach nicht weiterlei-ten. Dieser Paketverlust bewirkt ebenfalls das Ausbleiben entsprechender ACK–Pakete,wodurch ebenfalls nach einem Timeout noch einmal gesendet wird.

    Gehen ACK–Pakete selbst verloren, werden die dazugehörigen Daten auch timeout-basiert wiederholt gesendet. Ein weiterer Spezialfall sind SYN – und FIN –Pakete, beidenen auch die korrespondierende Antwort ausbleibt, wenn sie verloren gehen.

    28

  • A. Abbildungsverzeichnis

    3.1. Veranschaulichung des Aufbaus der einzelnen Komponenten (Adressen inKlammern) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

    4.1. Schematische Darstellung der Schichten des Protokollstacks . . . . . . . . 134.2. Schematische Darstellung des Protokoll–Flusses bei der Kommunikation

    durch die Schichten des Protokollstacks . . . . . . . . . . . . . . . . . . . 144.3. Schematische Darstellung der Kommunikation zwischen den Schichten

    mittels Transport–Queues. . . . . . . . . . . . . . . . . . . . . . . . . . . . 184.4. Interner Aufbau von Layer 2 mit den zwei Threads. . . . . . . . . . . . . . 204.5. Fluss–Diagramm des implementierten Sliding–Window–Algorithmus im

    Sender (ThreadL2SWOut). . . . . . . . . . . . . . . . . . . . . . . . . . . . 254.6. Fluss–Diagramm des implementierten Sliding–Window–Algorithmus im

    Empfänger (ThreadL2SWIn). . . . . . . . . . . . . . . . . . . . . . . . . . . 26

    29

  • B. Kommentierter Protokollausdruck einesTestlaufs

    B.1. SYN geht verloren

    === Router wirft Pakete weg - SYN-Flag verworfen ===mj@psi:~/rk/real$ java Layer3TestL0: SendL0: *** Start SendL0 ***L1: ThreadL1FromL2ToL0: *** Start ThreadL1FromL2ToL0 ***L1: ThreadL1FromL0ToL2: *** Start ThreadL1FromL0ToL2 ***L0: SendL0: *** Start RecvL0 ***L2: ThreadL2SWOut: NEW-Flag gesetzt! -> Baue Verbindung auf...L2: ThreadL2SWOut: Warte auf SYN,ACK von 3Timer: 4000 msTimer abgelaufenL2: ThreadL2SWOut: TimeOut beim Warten auf SYN,ACK von 3L3: Layer3Test: Konnte keine Verbindung herstellen!L3: Beende Thread...

    mj@psi:~/rk/real$ java RouterTestL1: ThreadL1Router: *** Start ThreadL1Router ***L0: SendL0: *** Start RecvL0 ***L0: SendL0: *** Start SendL0 ***| 3| 1| 5 | SYN | 0| 0| 1| 1 | |L1: ThreadL1Router: Paket ging verloren!

    B.2. ACKs und DATA gehen verloren

    === Router wirft Pakete weg - ACK-Flag verworfen ===mj@psi:~/rk/real$ java Layer3TestL0: SendL0: *** Start SendL0 ***L0: SendL0: *** Start RecvL0 ***L1: ThreadL1FromL2ToL0: *** Start ThreadL1FromL2ToL0 ***L1: ThreadL1FromL0ToL2: *** Start ThreadL1FromL0ToL2 ***L2: ThreadL2SWOut: NEW-Flag gesetzt! -> Baue Verbindung auf...L2: ThreadL2SWOut: Warte auf SYN,ACK von 3Timer: 4000 ms

    30

  • L2: ThreadL2SWIn: SYN,ACK - Flags gesetzt! -> ...L2: ThreadL2SWOut: SYN,ACK von 3 -> Verbindung hergestelltL2: ThreadL2SWOut: ACK(1) an 3L3: Layer2Test: Verbindung hergestellt!L3: Nachricht 0 an Netzwerk uebergebenL2: ThreadL2SWOut: DATA-Flag gesetztL2: ThreadL2SWOut: BuffNext: 0L2: ThreadL2SWOut: WinSize: 1L2: ThreadL2SWOut: Window ist voll -> Sende WindowL2: ThreadL2SWOut: Window ist voll -> Warte auf ACK(SeqNo)Timer: 400 msL2: ThreadL2SWIn: ACK - Flag gesetzt! -> an SendeThreadL2: ThreadL2SWOut: ACK(3) von 3L2: ThreadL2SWOut: WS == 1, WinSize von 3 == 20L3: Nachricht 1 an Netzwerk uebergebenL2: ThreadL2SWOut: DATA-Flag gesetztL2: ThreadL2SWOut: BuffNext: 0L2: ThreadL2SWOut: WinSize: 2L3: Nachricht 2 an Netzwerk uebergebenL2: ThreadL2SWOut: DATA-Flag gesetztL2: ThreadL2SWOut: BuffNext: 1L2: ThreadL2SWOut: WinSize: 2L2: ThreadL2SWOut: Window ist voll -> Sende WindowL2: ThreadL2SWOut: Window ist voll -> Warte auf ACK(SeqNo)Timer: 400 msTimer abgelaufenL2: ThreadL2SWOut: TimeOut beim Warten auf ACK(5)L2: ThreadL2SWOut: Window ist voll -> Sende WindowL2: ThreadL2SWOut: Window ist voll -> Warte auf ACK(SeqNo)Timer: 400 msL3: Nachricht 3 an Netzwerk uebergebenTimer abgelaufenL2: ThreadL2SWOut: TimeOut beim Warten auf ACK(5)L2: ThreadL2SWOut: Window ist voll -> Sende WindowL2: ThreadL2SWOut: Window ist voll -> Warte auf ACK(SeqNo)Timer: 400 msTimer abgelaufenL2: ThreadL2SWOut: TimeOut beim Warten auf ACK(5)L2: ThreadL2SWOut: Window ist voll -> Sende WindowL2: ThreadL2SWOut: Window ist voll -> Warte auf ACK(SeqNo)Timer: 400 msL2: ThreadL2SWIn: ACK - Flag gesetzt! -> an SendeThreadL2: ThreadL2SWOut: ACK(5) von 3L2: ThreadL2SWOut: WS == 2, WinSize von 3 == 20

    31

  • L3: Nachricht 3 an Netzwerk uebergebenL2: ThreadL2SWOut: DATA-Flag gesetztL2: ThreadL2SWOut: BuffNext: 0L2: ThreadL2SWOut: WinSize: 4L3: Nachricht 4 an Netzwerk uebergebenL3: Nachricht 5 an Netzwerk uebergebenL3: Nachricht 6 an Netzwerk uebergeben...

    mj@psi:~/rk/real$ java RouterTestL1: ThreadL1Router: *** Start ThreadL1Router ***L0: SendL0: *** Start RecvL0 ***L0: SendL0: *** Start SendL0 ***| 3| 1| 5 | SYN | 0| 0| 1| 1 | |L1: ThreadL1Router: Benutze ZielPort: ’10300’| 1| 3| 5 | ACK SYN | 0| 1| 20| 1 | |L1: ThreadL1Router: Benutze ZielPort: ’10100’| 3| 1| 24 | DATA | 2| 1| 1| 1 | Hallo FileServer: 0 |L1: ThreadL1Router: Benutze ZielPort: ’10300’| 1| 3| 5 | ACK | 1| 3| 20| 1 | |L1: ThreadL1Router: Benutze ZielPort: ’10100’| 3| 1| 24 | DATA | 3| 1| 2| 1 | Hallo FileServer: 1 |L1: ThreadL1Router: Paket ging verloren!| 3| 1| 24 | DATA | 4| 1| 2| 1 | Hallo FileServer: 2 |L1: ThreadL1Router: Benutze ZielPort: ’10300’| 3| 1| 24 | DATA | 3| 1| 2| 1 | Hallo FileServer: 1 |L1: ThreadL1Router: Paket ging verloren!| 3| 1| 24 | DATA | 4| 1| 2| 1 | Hallo FileServer: 2 |L1: ThreadL1Router: Benutze ZielPort: ’10300’| 3| 1| 24 | DATA | 3| 1| 2| 1 | Hallo FileServer: 1 |L1: ThreadL1Router: Paket ging verloren!| 3| 1| 24 | DATA | 4| 1| 2| 1 | Hallo FileServer: 2 |L1: ThreadL1Router: Paket ging verloren!| 3| 1| 24 | DATA | 3| 1| 2| 1 | Hallo FileServer: 1 |L1: ThreadL1Router: Benutze ZielPort: ’10300’| 1| 3| 5 | ACK | 2| 5| 20| 1 | |L1: ThreadL1Router: Benutze ZielPort: ’10100’...

    32

  • B.3. Paket geht kaputt

    === Router aendert Paket -> CRC-Check schlaegt fehl ===mj@psi:~/rk/real$ java Layer3TestFileSrvmj@psi:~/rk/real$ java Layer2TestFileServerL0: SendL0: *** Start SendL0 ***L0: SendL0: *** Start RecvL0 ***L1: ThreadL1FromL0ToL2: *** Start ThreadL1FromL0ToL2 ***L1: ThreadL1FromL2ToL0: *** Start ThreadL1FromL2ToL0 ***L2: ThreadL2SWIn: CRC-Check fehlgeschlagen! -> Paket verworfen

    mj@psi:~/rk/real$ java RouterTestL1: ThreadL1Router: *** Start ThreadL1Router ***L0: SendL0: *** Start RecvL0 ***L0: SendL0: *** Start SendL0 ***| 3| 1| 5 | SYN | 0| 0| 1| 1 | |L1: ThreadL1Router: Benutze ZielPort: ’10300’L0: SendL0: CRC (L2-PDU) auf Router veraendert

  • C. Klassenreferenz

    C.1. CommL1Router Klassenreferenz

    Öffentliche, statische Methoden

    • synchronized void setRandPackLost ()Abfrage, ob zufaellig Datenpakete ”verloren” gehen sollen.

    • synchronized void unsetRandPackLost ()Abfrage, ob zufaellig Datenpakete ”verloren” gehen sollen.

    • synchronized boolean isRandPackLost ()Abfrage, ob zufaellig Datenpakete ”verloren” gehen sollen.

    • synchronized boolean isDataLost ()Abfrage, ob aktuelle Datenpakete ”verloren” gehen sollen.

    • synchronized void setLoseData ()Die folgenden Datenpakete sollen ”verloren” gehen.

    • synchronized void unsetLoseData ()Die folgenden Datenpakete sollen ankommen.

    • synchronized boolean isAckLost ()Abfrage, ob aktuelle Quittungen ”verloren” gehen sollen.

    • synchronized void setLoseAck ()Die folgenden Quittungen sollen ”verloren” gehen.

    • synchronized void unsetLoseAck ()Die folgenden Quittungen sollen ankommen.

    • synchronized boolean isCRCError ()Abfrage, ob aktuelle Datenpakete eine falsche ”Prüfsumme” bekommen sollen.

    • synchronized void setCRCError ()

    34

  • Die folgenden Datenpakete sollen eine falsche ”Prüfsumme” bekommen.

    • synchronized void unsetCRCError ()Die folgenden Datenpakete sollen eine gueltige ”Prüfsumme” bekommen.

    C.1.1. Ausführliche Beschreibung

    Realisiert die Kommunikation zur Fehlersimulation zwischen der 1. Schicht des Routerund dem Router-Hauptprogramm.

    C.2. ConnectionState Klassenreferenz

    Öffentliche, statische Methoden

    • synchronized boolean getConnState ()Der Verbindungs-Status wird abgefragt.

    • synchronized void setConnected ()Der Verbindungsstatus wird auf ”verbunden” gesetzt.

    • synchronized void setDisconnected ()Der Verbindungsstatus wird auf ”getrennt” gesetzt.

    • synchronized byte getConnAddress ()Die Adresse des Verbindungspartners wird abgefragt.

    • synchronized void setConnAddress (byte address)Die Adresse des Verbindungspartners wird gesetzt.

    C.2.1. Ausführliche Beschreibung

    Realisiert die Kommunikation zum Verbindungszustand zwischen den beiden Threadsder 2. Schicht.

    C.3. Hex Klassenreferenz

    Öffentliche, statische Methoden

    • String byteToHex (byte data)Mehode, die ein Byte in einen Hex-String umwandelt.

    35

  • • String bytesToHex (byte[ ] data)Mehode, die ein Byte-Array in einen Hex-String umwandelt.

    • char toHexChar (int i)Mehode, die ein Zeichen in einen Hex-String umwandelt.

    C.3.1. Ausführliche Beschreibung

    Diese Klasse stellt Methoden zur Ausgabe von Zahlen in hexadezimalen Darstellung zurVerfuegung.

    C.4. Keyboard Klassenreferenz

    Klasse, um einfach Tastatureingaben zu realisieren.

    Öffentliche, statische Methoden

    • int readInt ()Liest einen ’int’-Wert von der Standardeingabe.

    • char readChar ()Liest ein Zeichen von der Standardeingabe.

    • double readDouble ()Liest einen ’double’-Wert von der Standardeingabe.

    • String readString ()Liest einen String von der Standardeingabe.

    • boolean eof ()Prüft, ob das Ende der Eingabe erreicht ist.

    Statische Paketattribute

    • boolean iseof = false• char c• int i• double d• String s• BufferedReader input

    36

  • C.4.1. Dokumentation der Datenelemente

    BufferedReader Keyboard.input [static, package]

    Initialisierung:

    new BufferedReader (

    new InputStreamReader(System.in),1)

    C.5. L1L0IDU Klassenreferenz

    L1L0IDU repraesentiert die Schnittstelle zwischen der 1. und der 0. Schicht.

    Öffentliche Methoden

    • L1L0IDU (byte b[ ], String hostname, int UDPport)Konstruktor.

    • byte[ ] getPacket ()Gibt das Paket als Byte-Array zurück.

    • L1PDU getL1PDU ()Gibt das Paket als L1PDU zurück.

    • int getPort ()Gibt den Port zurück.

    • String getHostname ()Gibt den Hostnamen zurück.

    • byte sizeof ()Gibt die Länge des Paketes zurück.

    C.6. L1PDU Klassenreferenz

    Realisiert die Protokoll-Dateneinheit für die 1. Schicht.

    Öffentliche Methoden

    • L1PDU (byte dst, byte src, byte size, byte[ ] payload)Konstruktor.

    • byte getDst ()Gibt die Zieladdresse zurück.

    • byte getSrc ()Gibt die Quelladresse zurück.

    • byte getSize ()

    37

  • Gibt die Größe des Payloads zurück.

    • byte[ ] getPayload ()Gibt den Payload als Byte-Array zurück.

    • int getlength ()Gibt die Länge des Paketes zurück.

    • byte[ ] getBytes ()Gibt das Paket als Byte-Array zurück.

    C.7. L2L1IDU Klassenreferenz

    L2L1IDU repraesentiert die Schnittstelle zwischen der 2. und der 1. Schicht.

    Öffentliche Methoden

    • L2L1IDU (byte b[ ], byte address)Konstruktor.

    • byte[ ] getPacket ()Gibt das Paket als Byte-Array zurück.

    • L2PDU getL2PDU ()Gibt das Paket als L2PDU zurück.

    • byte getAddress ()Gibt die Adresse zurück.

    • byte sizeof ()Gibt die Länge des Paketes zurück.

    C.8. L2PDU Klassenreferenz

    Realisiert die Protokoll-Dateneinheit für die 2. Schicht.

    Öffentliche Methoden

    • L2PDU (byte options, byte id, byte ackid, byte window, byte crc, byte[ ] payload)Konstruktor.

    • int getlength ()Gibt die Länge des Paketes zurück.

    • byte getOptions ()Gibt die Optionen zurück.

    • byte getAckId ()

    38

  • Gibt die AckID zurück.

    • byte getId ()Gibt die ID zurück.

    • byte getWindow ()Gibt die Größe des Window-Puffers zurück.

    • byte getCRC ()Gibt die Prüfsumme zurück.

    • void setCRC (byte b)Setzt die Prüfsumme.

    • byte[ ] getPayload ()Gibt den Payload als Byte-Array zurück.

    • byte[ ] getBytes ()Gibt das Paket als Byte-Array zurück.

    Öffentliche, statische Methoden

    • L2PDU BytesToL2PDU (byte[ ] b)Erstellt aus dem übergebenen Byte-Array eine L2PDU.

    Statische öffentliche Attribute

    • final byte headerlength = 5

    C.9. L3L2IDU Klassenreferenz

    L3L2IDU repraesentiert die Schnittstelle zwischen der 3. und der 2. Schicht.

    Öffentliche Methoden

    • L3L2IDU (byte b[ ], byte address, byte options)Konstruktor.

    • byte[ ] getPacket ()Gibt das Paket als Byte-Array zurück.

    • byte getAddress ()Gibt die Adresse zurück.

    • byte getOptions ()Gibt die Optionen zurück.

    39

  • C.10. Queue Klassenreferenz

    Öffentliche Methoden

    • synchronized void put (Object newElement) throws InterruptedExceptionLegt ein Objekt in die Queue.

    • synchronized void alert (long TimeOut) throws InterruptedException• synchronized Object get () throws InterruptedException• synchronized Object get (int TimerNo) throws InterruptedException

    C.10.1. Ausführliche Beschreibung

    Queues dienen dem synchronisierten Datenaustausch zwischen den einzelnen Threads und auch denjeweiligen Hauptprogrammen.

    C.10.2. Dokumentation der Elementfunktionen

    synchronized void Queue.alert (long TimeOut) throws InterruptedException

    Realisiert einen Timeout in Millisekunden an der Queue. Darf nur aufgerufen werden, wenn sicher ist,dass Queue nicht überlaufen kann!

    synchronized Object Queue.get (int TimerNo) throws InterruptedException

    Holt ein Objekt aus der Queue. Falls die Queue leer ist, wird solange gewartet, bis die Queue ein Objektenthält.

    synchronized void Queue.put (Object newElement) throws InterruptedException

    Der parameterlose Konstruktor legt keine Zeiteinschränkung fest, mit der ein Thread auf eine Queuewartet.

    C.11. RecvL0 Klassenreferenz

    Empfängt Pakete von der 0. Schicht für alle 4 Stationen.

    Öffentliche Methoden

    • void closeSocketAndInterrupt ()Schliesst den UDP-Socket (falls offen) und beendet den Thread durch Interrupt.

    • RecvL0 (Queue quOut, String hostname, int ownPort)Konstruktor.

    • void run ()Thread.

    40

  • C.12. RecvL3 Klassenreferenz

    Empfängt Pakete aus der 2. Schicht für den Client, den Nameserver und den Fileserver.

    Zusammengehörigkeiten von RecvL3:

    RecvL3

    Queue

    quOutquIn

    Öffentliche Methoden

    • RecvL3 (Queue quIn, Queue quOut)Konstruktor.

    • void run ()Thread.

    C.13. SendL0 Klassenreferenz

    Sendet Pakete auf die 0. Schicht für alle 4 Stationen.

    Zusammengehörigkeiten von SendL0:

    SendL0

    L1L0IDU

    quElIn

    Öffentliche Methoden

    • void closeSocketAndInterrupt ()Schliesst den UDP-Socket (falls offen) und beendet den Thread durch Interrupt.

    • SendL0 (Queue quIn)Konstruktor.

    • void run ()Thread.

    41

  • C.14. ThreadL1FromL0ToL2 Klassenreferenz

    Zusammengehörigkeiten von ThreadL1FromL0ToL2:

    ThreadL1FromL0ToL2

    L1PDU

    L1Packet

    L1L0IDU

    quElIn

    Öffentliche Methoden

    • ThreadL1FromL0ToL2 (Queue quIn, Queue quOut, byte ownAddress)Konstruktor.

    • void run ()Thread.

    C.14.1. Ausführliche Beschreibung

    Empfängt Pakete aus der 0. Schicht für den Client, den Fileserver oder den Nameserver und reicht diesean die 2. Schicht weiter, falls die Zieladresse mit der der jeweiligen Station übereinstimmt.

    C.15. ThreadL1Router Klassenreferenz

    Zusammengehörigkeiten von ThreadL1Router:

    ThreadL1Router

    L1L0IDU

    quElIn

    Öffentliche Methoden

    • ThreadL1Router (Queue quIn, Queue quOut)Konstruktor.

    • void run ()Thread.

    C.15.1. Ausführliche Beschreibung

    Empfängt Pakete des Router aus der 0. Schicht, bestimmt den Zielhost (aus der Rooting-Tabelle) undsendet die Pakete wieder auf die 0. Schicht. Hier werden Übertragungsfehler simuliert.

    42

  • C.16. ThreadL2Alert Klassenreferenz

    ThreadL2SWOut ist ein Implementation des ausgehenden Sliding Window (Sender)-Algotithmus - Schicht2.

    Zusammengehörigkeiten von ThreadL2Alert:

    ThreadL2Alert

    Queue

    qu

    Öffentliche Methoden

    • ThreadL2Alert (Queue qu, long TimeOut)• void run ()

    C.17. ThreadL2SWOut Klassenreferenz

    ThreadL2SWOut ist ein Implementation des ausgehenden Sliding Window (Sender)-Algotithmus - Schicht2.

    Zusammengehörigkeiten von ThreadL2SWOut:

    ThreadL2SWOut

    L2PDU

    L2PDUOut

    L3L2IDU

    quElIn

    L2L1IDU

    quElOut

    ThreadL2Alert

    AckTimeOut

    Queue

    statequOutSWInSWOut

    qu

    Öffentliche Methoden

    • ThreadL2SWOut (Queue quIn, Queue quOut, Queue statequOut, Queue SWInSWOut)• void run ()

    Paketattribute

    • ThreadL2Alert AckTimeOut = new ThreadL2Alert(SWInSWOut, Def.ACK TIMEOUT)

    C.18. Tools Klassenreferenz

    Klasse für Hilfsmethoden, die alle Stationen benutzen koennen.

    43

  • Öffentliche, statische Methoden

    • synchronized void printPacket (String prefix, L1PDU packet)• synchronized void printPacket (L1PDU packet)

    Gibt das gesamte Packet der 1. Schicht aus.

    • byte[ ][ ] addPacketToWindow (byte window[ ][ ], byte packetno, byte[ ] packet)Speichert das Packet ’packet’ an der Stelle ’packetno’ im Windowspuffer ’window’.

    • byte[ ] copyByteArray (byte src[ ], int offset, int length)• byte[ ] concatByteArrays (byte first[ ], byte second[ ])

    Das Byte-Feld ’second’ wird an das Ende von ’first’ angehängt.

    • void printBytes (byte b[ ])Die einzelnen Werte von ’b’ werden der Reihe nach ausgegeben.

    • boolean isBitSet (byte b, byte flag)isBitSet gibt true zurück, wenn flag in b gesetzt ist, sonst false.

    • byte[ ] cutByteArray (byte bytes[ ], int posFirstCut)

    C.18.1. Dokumentation der Elementfunktionen

    byte [ ] Tools.copyByteArray (byte src[ ], int offset, int length) [static]

    Aus dem Byte-Feld ’src’ werden ab Position ’offset’ ’length’ viele Bytes in das Rueckgabe-Feld kopiert.

    byte [ ] Tools.cutByteArray (byte bytes[ ], int posFirstCut) [static]

    ”Schneidet” aus dem Byte-Feld ’bytes’ ab der übergebenen Position alle Bytes heraus und gibt den Restals Resultat zurück.

    synchronized void Tools.printPacket (String prefix, L1PDU packet) [static]

    Gibt das gesamte Packet der 1. Schicht aus und stellt den String ’prefix’ voran.

    44

    1 Einleitung2 Aufgabenstellung3 Überlegungen zur Herangehensweise3.1 Vereinfachungen3.2 Aufbau3.2.1 Adressierungsarten3.2.2 Komponenten

    3.3 Implementationstechniken3.3.1 Modellierung3.3.2 Fehler-- und Flusskontrolle3.3.3 Sprache

    4 Beschreibung der Implementierung4.1 Schichten des Protokollstacks4.1.1 Überblick über die Schichten des Protokollstacks4.1.2 Aufbau des Protokollstacks4.1.3 Kommunikation über den Protokollstack

    4.2 Protokolle4.2.1 Layer 0: Übertragungsprotokoll4.2.2 Layer 1: Wegewahlprotokoll4.2.3 Layer 2: Verbindungsprotokoll4.2.4 Layer 3: Applikationsprotokolle4.2.5 gemeinsamer Protokollstack von Layer 1 bis 3

    4.3 Schnittstellen zwischen den Schichten4.3.1 ICI / PDU / IDU

    4.4 Einblick in die Verbindungsschicht4.4.1 Verbindungsaufbau4.4.2 Verbindungsabbau4.4.3 Fluss-- und Fehlerkontrolle

    4.5 Abläufe4.5.1 Ziel der Beispiels--Kommunikation4.5.2 Hostnamen auflösen4.5.3 Datei herunterladen4.5.4 Fehlerfälle4.5.5 Flusssteuerung4.5.6 Besondere Situationen

    5 Testen der Implementierung5.1 Modifikationen am Router5.2 Vorgehensweise beim Testen

    A AbbildungsverzeichnisB Kommentierter Protokollausdruck eines TestlaufsB.1 SYN geht verlorenB.2 ACKs und DATA gehen verlorenB.3 Paket geht kaputt

    C KlassenreferenzC.1 CommL1Router KlassenreferenzC.1.1 Ausführliche Beschreibung

    C.2 ConnectionState KlassenreferenzC.2.1 Ausführliche Beschreibung

    C.3 Hex KlassenreferenzC.3.1 Ausführliche Beschreibung

    C.4 Keyboard KlassenreferenzC.4.1 Dokumentation der Datenelemente

    C.5 L1L0IDU KlassenreferenzC.6 L1PDU KlassenreferenzC.7 L2L1IDU KlassenreferenzC.8 L2PDU KlassenreferenzC.9 L3L2IDU KlassenreferenzC.10 Queue KlassenreferenzC.10.1 Ausführliche BeschreibungC.10.2 Dokumentation der Elementfunktionen

    C.11 RecvL0 KlassenreferenzC.12 RecvL3 KlassenreferenzC.13 SendL0 KlassenreferenzC.14 ThreadL1FromL0ToL2 KlassenreferenzC.14.1 Ausführliche Beschreibung

    C.15 ThreadL1Router KlassenreferenzC.15.1 Ausführliche Beschreibung

    C.16 ThreadL2Alert KlassenreferenzC.17 ThreadL2SWOut KlassenreferenzC.18 Tools KlassenreferenzC.18.1 Dokumentation der Elementfunktionen