Unix­1 im Wintersemester 1994/95

6. Übungsblatt

Dieses Übungsblatt enthält ähnlich wie das erste eine Sammlung von praktischen Aufgaben, die nicht alle bearbeitet werden müssen.  Ihr könnt Euch eine der gestellten Aufgaben zur Bearbeitung aussuchen.  Beachtet bitte, daß für die einzelnen Aufgaben je nach Schwierigkeitsgrad und Umfang unterschiedliche Maximalpunktzahlen zu erreichen sind.  Richtet Eure Wahl also nicht nur nach persönlichem Interesse, sondern auch nach Eurem aktuellen Punktestand.  Die Noten für die Übungen ergeben sich wie folgt aus der Gesamtpunktzahl der Übungsblätter:

Die Aufgaben enthalten neben der Grundaufgabenstellung noch Zusätze, die weitere Funktionalitäten realisieren sollen und zusätzlich Punkte bringen.


Aufgabe 1 (20 Punkte)
Builtin­Kommando als Client ähnlich rwho(1).

Erweitert Euren msh um das builtin­Kommando mrwho Die Ausführung dieses Kommandos soll in dem Modul socket.c mit Hilfe von Streamsockets in der Internet­Domain bei dem Serverprozeß unix1­daemon beantragt werden.  Dieser Serverprozeß wird auf dem Rechner kraftbus.cs.tu-berlin.de ausgeführt und ist über die Portnummer 4711 erreichbar.  Sollte der Daemon nicht installiert sein (der Aufruf von connect() scheitert), könnt Ihr Euch an einen Tutor wenden. 

mrwho soll als builtin­Kommando ähnlich dem rwho­Kommando im C­Shell implementiert werden.  Nach Anfrage beim Server erhält der Client (also socket.c) 0 bis n Strings der Länge 18 Zeichen zurück.  Diese haben das Format username:hostname, wobei username und hostname jeweils bis zu 8 Buchstaben lang sein können. 

Da mrwho nur die Benutzer­ und Hostnamen der Unix1­Bereiche zurückliefern soll, müßt Ihr Euch beim Starten Eures msh durch Anfrage beim Server in die entsprechende Datei eintragen lassen und beim Verlassen des msh das Löschen aus dieser Datei beantragen.  Diese Anfragen sollen durch die Funktionen void do_login() und void do_logoff() in socket.c realisiert werden.  Die beiden Funktionen sollen aus main.c aufgerufen werden.  Bei einer Anfrage zum Schreiben oder Löschen liefert der Server die Zeichenkette "ok" zurück, wenn die Funktion richtig ausgeführt werden konnte, ansonsten eine (maximal 18 Byte lange) Fehlermeldung. 

Die Protokollschnittstelle zum Server sieht vor, daß in einer 18­Byte­Nachricht eine Anforderung übermittelt wird.  In einer Antwortnachricht, die ebenfalls immer 18 Byte lang ist, werden die möglichen Rückgabewerte beschrieben.  In dem Puffer, der dem Server mit write() übergeben wird, müssen für die Ausführung der einzelnen Funktionen zuerst folgende ASCII­Zeichen übergeben werden:

  1. für das Eintragen von Benutzer­ und Hostnamen,
  2. für die Anfrage (mrwho) und
  3. für das Löschen von Benutzer­ und Hostnamen.

Zusatzaufgaben zu Aufgabe 1:

(Hierzu ist jeweils eine kurze Dokumentation der in Aufgabe 2 verlangten Art zu schreiben.)

Aufgabe 1a (15 Punkte):  Passender Server

Schreibt einen Server, der genau die Aufgaben wahrnimmt, die unser für die Aufgabe vorgegebener Server erfüllt.  Er soll für jede Clientanfrage einen neuen Prozeß starten, der die Anfrage dann bearbeitet und das Format des übergebenen Strings auf Korrektheit prüfen.  Die Bearbeitung dieses Teils ist Voraussetzung für 1b und 1c.

Aufgabe 1b (10 Punkte)  Semantische Überprüfung der Parameter

Der übergebene String ist auch auf inhaltliche Korrektheit zu prüfen.  Es muß also kontrolliert werden, ob sowohl der angegebene Benutzer als auch der Rechner überhaupt existieren und gegebenenfalls eine Fehlermeldung an den Client gesandt werden. 

Aufgabe 1c (5 Punkte)  Nebenläufigkeitskontrolle

Zur Vermeidung nebenläufiger schreibender Zugriffe auf die Benutzerliste durch mehrere Kindprozesse des Servers ist die Liste bei Schreiboperationen durch den flock()­Mechanismus zu schützen.


Aufgabe 2 (30 Punkte)
Einfache Client­Server­Datenbankanwendung

Implementiert eine einfache Datenbank als Client­Server­Anwendung. Der Server soll dabei als Unix­Daemon implementiert sein, die eigentliche Datenbankdatei verwalten und Anfragen (lesend oder schreibend) von einer ebenfalls zu implementierenden Clientanwe ndung beantworten bzw. bearbeiten. 

Der Inhalt der Datenbank ist Euch überlassen; ein Datensatz soll aber mindestens aus drei Feldern bestehen, wie z.B. bei einer Adressenkartei.  Der Server soll dem Client die Operationen Einfügen, Löschen, Lesen und SortierteAusgabe zur Verfügung stellen.  Zur sortieren Ausgabe aller Datensätze dient ein durch den Server festgelegtes Schlüsselfeld, z.B. der Nachname bei der Adressenkartei.  Für die Löschoperation muß der Client einen kompletten Datensatz übergeben, den der Server nur bei exakter Übereinstimmung löscht. Beim Lesen nur eines Datensatzes muß der Client den Inhalt des Schlüsselfeldes übergeben.  Falls mehrere gleiche Schlüsselfelder existieren, liefert der Server trotzdem nur den ersten gefundenen Datensatz zurück. 

Client und Server kommunizieren über Stream­ oder Datagramm­Sockets miteinander.  Der Server startet bei jeder Anfrage durch einen Client einen neuen Prozeß, der die Anfrage bearbeitet.  Potentiell können mehrere Clients gleichzeitig auf den Server zugreifen; dieser Fall ist auch zu testen.  Die dabei auftretenden Nebenläufigkeitsprobleme werden in einer Zusatzaufgabe behandelt. 

Eure Aufgabe ist neben der Implementierung von Client und Server die Entwicklung eines einfachen geeigneten Protokolls zwischen beiden und das Schreiben einer kurzen Dokumentation mit Bedienungsanleitung für Euer Produkt.  In der Dokumentation sollt Ihr den Aufbau Eurer Applikation beschreiben, Eure Designentscheidungen begründen und auf Probleme bei der Implementierung eingehen.  Der Dokumentationsteil geht zu einem Drittel in die Gesamtbewertung ein.

Zusatzaufgaben zu Aufgabe 2:

(ebenfalls jeweils zu dokumentieren)

Aufgabe 2a (5 Punkte)  Nebenläufigkeitskontrolle

Implementiert eine simple Nebenläufigkeitskontrolle für den Server mit Hilfe der flock()­Funktionen.  Dabei soll bei einem schreibenden Zugriff die gesamte Datenbankdatei für weitere Schreibzugriffe gelockt werden, damit durch den möglichen gleichzeitigen Zugriff anderer Kindprozesse des Servers keine Nebenläufigkeitsprobleme entstehen.  (lockf() darf alternativ verwendet werden.)

Aufgabe 2b (10 Punkte)  Zugriffsschutz und ­kontrolle

Der Client soll bei jeder Anfrage an den Server die UID des Benutzers mit übergeben.  Der Server prüft dann an Hand einer kleinen Datenbasis, auf die nur derjenige Zugriff hat, dem der Server ,,gehört'', ob der Benutzer überhaupt zugriffsberechtigt ist.  Dabei soll zwischen lesendem und schreibendem Zugriff unterschieden werden können.  Beispielsweise können in einer Datei die Benutzernamen aller Leute stehen, die lesenden und schreibenden Zugriff haben, in einer anderen die Logins derer, die nur lesen dürfen.  Wer in beiden Dateien nicht vorkommt, darf auch nicht zugreifen.  Für die Überprüfung von Lesezugriffen ist ein Mechanismus vorzusehen, der dem Server mitteilt, daß allen Benutzern der Zugriff gestattet ist (z.B. ein spezieller Login).  Bei einem als illegal erkannten Zugriff ist dem Benutzer dies durch eine Fehlermeldung anzuzeigen.

Aufgabe 2c (5 Punkte)  Protokollierung von Zugriffen

Der Server soll alle schreibenden und illegalen Zugriffe in einer weiteren Datei im Klartext mitprotokollieren.  Zu einem Protokolleintrag gehören der Name des zugreifenden Benutzers, Uhrzeit und Datum, die Art des Zugriffs, gegebenenfalls die beim Zugriff übergebenen Parameter (also der Datensatz) und bei einer illegalen Operation der Grund der Ablehnung.  Ist der Zugriffsschutz aus 2b nicht implementiert, sind nur die Schreibzugriffe festzuhalten.

Aufgabe 2d (5 Punkte)  Suchfunktionen

Der Server soll zusätzlich zu den bereits vorhandenen die Funktion Suchen anbieten.  Der Client übergibt hierfür einen Suchstring (ohne Wildcards).  Der Server durchsucht alle Felder seiner Datensätze nach diesem String und übergibt dem Client alle Datensätze, bei denen ein Match aufgetreten ist.  Darunter fallen auch Matches auf Teilstrings, d.h. der Suchstring muß kein vollständiges Datenfeld enthalten.

Aufgabe 2e (5 Punkte)  Wechsel des Schlüsselfeldes

Die Parameter der Operationen Lesen und SortierteAusgabe sollen so erweitert werden, daß für die jeweilige Operation ein anderes als das Standardfeld als Schlüsselfeld angegeben werden kann.


Aufgabe 3 (50 Punkte)
Rechnen mit großen Zahlen als Client­Server­Anwendung

Entwickelt einen Server, der Clients Operationen auf große Integers mit bis zu mehreren hundert Stellen zur Verfügung stellt.  Der Client soll über ein geeignetes Protokoll auf Basis von BSD­Sockets die Parameter und die gewünschte Operation spezifizieren können.  Der Server gibt ihm danach das Ergebnis zurück.  Als Operationen sollen mindestens Addition, Subtraktion, Multiplikation, Division, Vorzeichenwechsel, Potenzierung und die elementaren Vergleichsoperationen (gleich, ungleich, größer, kleiner, größer­gleich, kleiner­gleich) vorhanden sein.

Es dürfte praktisch sein, alle Zahlen im Client und im Protokoll als Strings zu repräsentieren, damit das für die Rechenoperationen benötigte und unter Umständen komplizierte Zahlenformat ganz im Server verborgen bleibt. 

Neben dem Server ist ein Client zu entwickeln, der die angebotenen Operationen sinnvoll testet.  Außerdem ist eine Dokumentation zu erstellen, die den Aufbau Eurer Applikation, das gewählte Zahlenformat und die bei den Rechenoperationen verwendeten Algorithmen beschreibt.  Sie geht etwa zu 25% in die Gesamtbewertung ein.

Zusatzaufgaben zu Aufgabe 3:

(ebenfalls zu dokumentieren)

Aufgabe 3a (5 Punkte)  Operation GGT

Der Server soll zusätzlich die Operation GGT (größter gemeinsamer Teiler) anbieten.

Aufgabe 3b (5 Punkte)  Primzahltest

Der Server soll prüfen können, ob eine durch den Client übergebene Zahl eine Primzahl ist und einen Booleschen Wert als Ergebnis liefern.  Es sind auch probalistische Tests mit ausreichend hoher Wahrscheinlichkeit erlaubt.

Aufgabe 3c (10 Punkte)  Primfaktorzerlegung

Der Server soll eine übergebene Zahl in ihre Primfaktoren zerlegen können.  Dem Client wird die Liste der Faktoren nach abgeschlossener Faktorisierung komplett zurückgeliefert.  Für viele Algorithmen ist es übrigens praktisch, vorher 3a und 3b zu implementieren. 

Aufgabe 3d (10 Punkte)  Paralleler Client

Implementiert einen Client, der nebenläufig Operationen an mehrere auf verschiedenen Rechnern laufende Server verteilt, nichtblockierend (per select()) auf die Ergebnisse wartet, diese wiederum für neue Operationen nutzt, usw. 

Der Client soll also seinen internen Ablauf durch Aufgabenverteilung über mehrere Server seinen internen Ablauf weitgehend parallelisieren.  Überlegt Euch eine Anwendung für die dies sinnvoll erscheint (z.B. wieder eine Primfaktorzerlegung).

(Das liegt natürlich weit über dem Unix­1­Niveau, aber vielleicht mag es ja jemand just for fun ausprobieren.)