4. Aufgabe

Zur Vorbereitung auf den Termin lesen Sie bitte das Skript zum Block E und machen Sie sich mit den C-Funktionen, die benötigt werden, vertraut (in welcher C-Bibliothek sind sie zu finden, welche Parameter benötigen sie und welche Information liefert ihr Rückgabewert). Es ist außerdem empfehlenswert sich mit der kurzen Übung intensiver zu beschäftigen. Einen Shortcut zu der Funktionsübersicht finden sie auch in der Navigation rechts.

Socket-Funktionen

Frischen Sie ihre C-Kenntnisse auf. Ein gute Einführung finden Sie hier:

C Tutorial
C++ Tutorial

Empfehlenswert sind auch die Folien der Vorlesung der Unit 2 (Communication Services and Protocols).

Wer tiefer in die Socket-Programmierung einsteigen möchte, dem sei das Buch „TCP/IP Sockets in C: Practical Guide for Programmers“ von Michael J. Donahoo und Kenneth L. Calvert empfohlen. Auch das Buch „Linux-UNIX-Programmierung“ von Jürgen Wolf (Kapitel 11) ist empfehlenswert. „Beej′s Guide to Network Programming“ und Perkins „NS3 Lab 1 – TCP/IP Network Programming in C“ sind ebenfalls empfehlenswerte Referenzen.

TCP/IP Sockets in C: Practical Guide for Programmers
Beej's Guide to Network Programming
NS3 Lab 1 – TCP/IP Network Programming in C
Linux-UNIX-Programmierung

Auf alle Fälle ist es empfehlenswert, einige Programmbeispiele zu studieren, die in einer Vielzahl im Internet zu finden sind.

Programmbeispiel

Ihre Aufgabe ist es, einen Stream Socket in der Programmiersprache C zu implementieren. Der Client soll Text, der über die Tastatur eingegeben wird, zu einem Server senden, der den Text auf dem Bildschirm ausgibt. Verwenden Sie dazu bitte die zur Verfügung gestellten Dateien stream_client.c bzw. stream_server.c und Makefile. Bevor Sie mit der Implementierung beginnen, müssen Sie die folgenden Aspekte berücksichtigen:


4.1 Programmgerüst

In der Regel ist es kein Problem, die Abfolge von Funktionen zu programmieren. Es gestaltet sich als viel schwieriger, den Funktionen die korrekten Parameter in der korrekten Darstellung zu übergeben. Werden hierbei Fehler gemacht, passiert gar nichts ohne, dass der Grund zunächst erkennbar ist. Die Korrektur der Fehler benötigt in solchen Fällen sehr viel Zeit. Um Ihnen dies zu vereinfachen, existiert bereits ein fertiges Programm. Sie können nun in diesem Programm einzelne Programmteile durch Ihren eigenen Quelltext ersetzen. Hierzu ist in jeder Funktion in den oben genannten Dateien ein Schalter vorhanden. Wenn der Schalter auf 1 gesetzt wird, verwenden Sie ihren eigenen Quellcode (siehe folgenden Beispielcode), wenn er ungleich eins ist, wird der vorbereitete Code ausgeführt.

#if 1

void someFunctionHeader( void someParameters )
{
	//TODO irgendwas
}

#endif
Listing 5: Aufbau einer Funktion im Programmgerüst

Dadurch werden Sie in die Lage versetzt, selektive Änderungen durchzuführen und deren Auswirkungen zu untersuchen. Wie Sie am Beispielcode erkennen, ist der Schalter mittels einer Präprozessor-Anweisung realisiert. Der Code zwischen den #if- und #endif-Anweisungen wird nur ausgeführt, wenn der Wert der #if-Anweisung 1 ist. Wenn der Wert 0 ist, dann wird eine Funktion in der vorhandenen Bibliothek des Programmgerüsts verwendet.

Zu Beginn steht in allen #if-Anweisungen der Wert 0. Das Programm ist somit von Anfang an kompilierbar und lauffähig und kann durch Änderung der entsprechenden Quelltextzeilen zu 1 sukzessive durch eigene Implementationen ersetzt werden. Hierdurch soll Ihnen die Möglichkeit gegeben werden, eigene Funktionen und vorgegebene Funktionen in beliebiger Konstellation zu laden, was die Fehlersuche stark vereinfachen sollte. Die genauen Funktionsbeschreibungen und Aufgabenstellungen sind in der gegebenen Quelltext-Datei aufgeführt, dennoch soll hier ein kurzer Überblick, verbunden mit dem empfohlenen Arbeitsablauf gegeben werden.

4.1.1 Dateien und Verzeichnisse

Alle zur Verfügung gestellten Dateien für diesen Termin befinden sich als Kopie im ISIS und in Ihrem Home-Verzeichnis im Ordner „StreamSocket“. In diesem Ordner befinden sich der Ordner lib und die Dateien Makefile, stream_client.c und stream_ server.c, sowie die Dateien stream_client.h und stream_server.h.

Makefile: Das Makefile erleichtert Ihnen das Übersetzen des Quellcodes zu einem ausführbaren Programm, indem es alle benötigten Anweisungen ausführt. Sie geben lediglich den Befehl

make

ein. Vor jedem neuen make-Befehl empfehlen wir make clean aufzurufen.

lib: Dieser Ordner enthält Bibliotheken mit vordefinierten Funktionen für gängige Betriebssysteme, die zur Verwendung des Clients/ Servers benötigt werden. Unterstützt werden Linux und MacOS X.

stream_client.c / stream_server.c: Diese Dateien enthalten den Quellcode des Clients und des Servers. Jede der beiden Dateien lässt sich im Wesentlichen in drei Abschnitte gliedern:


4.2 Empfohlene Vorgehensweise

Folgende Vorgehensweise hat sich in der Vergangenheit bewährt:

4.2.1 Vertrautmachen mit der Umgebung

Bevor die Programme stream_client und stream_server ausgeführt werden können, müssen Sie zunächst übersetzt und mit einem Linker gebunden werden. Dies geschieht automatisch durch Eingabe des Befehls make. Hierzu starten Sie zunächst das Programm Terminal. Hierauf öffnet sich ein Fenster mit einer Shell. In der Shell wechseln Sie in das Verzeichnis StreamSocket in ihren Home-Bereich und geben am Prompt den Befehl make ein.

Daraufhin werden die beiden Programme stream_client und stream_server erzeugt. Starten Sie zunächst das Programm stream_server. Der Server wird durch Eingabe des Befehls:

./stream_server <ip_adresse> <port>

gestartet. Die fest eingestellte ip_adresse für den Client ist das LoopBack-Interface (Adresse 127.0.0.1) und der Port 3850. Für den Server wird der Wert INADDR_ANY der Adresse zugewiesen. Optional kann der im Programm fest eingestellte port und die ip_adresse durch Angabe der Argumente verändert werden. Dies ist beispielsweise dann notwendig, wenn der Client und der Server auf verschiedenen Rechnern laufen.

Öffnen Sie nun ein neues Fenster im Programm Terminal. Wechseln Sie in das Verzeichnis StreamSocket und starten durch Eingabe des Befehls

./stream_client <ip_adresse > <port>

den Client.

Wenn Sie alle Anweisungen korrekt durchgeführt haben, können Sie wahlweise am Client oder am Server einen Text eingeben, der dann am jeweils anderen Fenster ausgegeben wird.

4.2.2 Implementation des TCP Clients

In diesem Abschnitt wird beschrieben, welche Stellen im Quelltext des Clients modifiziert werden müssen und welche Schritte zum Erstellen des Programms notwendig sind.

Starten Sie einen Texteditor und öffnen dann die Datei stream_client.c. Diese befindet sich in Ihrem Home-Bereich im Verzeichnis StreamSocket. Vollziehen Sie die gegebene Struktur des Quelltextes nach. Die folgenden Funktionen müssen von Ihnen ergänzt werden:

Sie haben die Möglichkeit, alle Änderungen in der Datei stream_client.c auf einmal oder jede der aufgeführten Funktionen einzeln zu modifizieren.

Empfehlenswert ist eine schrittweise Implementation. Achten Sie darauf, dass bei der modifizierten Funktion der Wert der #if-Anweisung von 0 auf 1 geändert werden muss. Ansonsten hat Ihre Modifikation keine Wirkung.

Nach jedem Schritt speichern Sie die Datei und führen das make-Kommando aus. Wenn das make-Kommando nicht erfolgreich ausgeführt wurde, müssen Sie den Quelltext korrigieren, bis das Kommando fehlerfrei abgeschlossen wurde. Anschließend testen Sie durch Ausführen des Programms und überprüfen, ob ihre Änderung das gewünschte Verhalten zeigt.

4.2.3 Implementation des TCP Servers

Die Schritte, die zum Erzeugen des Servers notwendig sind, entsprechen im Wesentlichen denen des Clients. Unterschiedlich ist lediglich der Name der Quell- und der Ausführbaren-Datei (stream_server.c bzw. stream_server).

Da der Server das Pendant des Client ist, sind in ihm vielen Funktionen identisch mit denen des Clients. Deshalb werden nur die zusätzlichen Funktionen beschrieben: