![]() |
Praktikum Internet-Technologievon Prof. Jürgen Plate |
Die Domain für alle Rechner ist da.private.hm.edu. Dabei steht "da" für den Standort Dachauerstr./Lothstr. und "private" bedeutet, daß der Rechner im privaten (von aussen nicht erreichbaren) Netz steht.
Der Apache-Webserver ist nur auf lc1 installiert. Da Sie nur an X-Terminals sitzen und doch jeder sein eigenes Webverzeichins haben soll, verwenden wir die Möglichkeit der sogenannten User-Directories:
Die Dateien in ihrem Home-Directory sind natürlich auf allen drei Systemen (lc1, lc2 und lc3) verfügbar, auch wenn der Webserver nur auf lc1 läuft.
Die MySQL-Datenbank befindet sich (wie der Webserver) nur auf lc1. Der Datenbank-Zugriff für Ihre CGI-Scripte erfolgt dann mit folgenden Angaben:
mysql -u tom -p -h lc1Einfacher geht es jedoch mit einer webbasierten Oberfläche namens "phpmyadmin". Diese wird über folgende URL aufgerufen:
http://lc1/phpmyadminAuch hier ist danach User- und Passworteingabe gefordert.
Die Domain für alle Rechner ist ebenfalls da.private.hm.edu. Dabei steht "da" für den Standort Dachauerstr./Lothstr. und "private" bedeutet, daß der Rechner im privaten (von aussen nicht erreichbaren) Netz steht.
Für einige Aufgaben ist die Root-Berechtigung notwendig.
Der Wechsel in die Rolle des Superusers erfolgt mit dem Kommando
sudo. Um eine Root-Shell zu erlangen, geben Sie demnach
sudo su ein. Der Login auf anderen Rechnern erfolgt mittels
der Secure Shell (ssh <user>@<rechner>) und
zum Kopieren wird Secure Copy (scp) verwendet.
Der Apache-Webserver ist auf allen Rechnern installiert. Unter Ubuntu befinden sich die beiden Verzeichnisse, auf die es ankommt, an verschiedenen Stellen:
sudo bash # root-Berechtigung erlangen chown -R mond /var/www /usr/lib/cgi-bin # Verzeichnisse an user 'mond' uebergeben chmod 775 /var/www /usr/lib/cgi-bin # Zugriffsrechte setzen ln -s /var/www www # Document-Root nun per Link leicht erreichbar ln -s /usr/lib/cgi-bin cgi-bin # das Gleiche fuer cgi-bin exit # root-bash wieder verlassenSie können nun vom Homedirectory direkt in die beiden Verzeichnisse des Webservers wechseln und dort auch Dateien anlegen. Denken Sie daran, dass Programme im Verzeichnis cgi-bin immer erst Execute-Berechtigung bekommen müssen (chmod 755 proggi.pl).
Anmerkung:
Bei Linux ist Perl per Default dabei. Wenn Sie unter Windows mit
Perl arbeiten wollen, können Sie sich das kostenlose Activestate-Perl herunterladen:
www.activestate.com/activeperl/downloads
(Wer will, kann sich auch gleich noch ein Python holen: www.activestate.com/activepython/downloads)
Sowohl Eltern- als auch Kindprozess arbeiten das Perlscript weiter ab, beginnend mit der Anweisung nach dem fork-Aufruf. Klassischerweise ist dies eine Verzweigung, deren einer Zweig vom ursprünglichen Prozess ausgeführt wird, der andere vom Kind. Damit sich das Kind beendet, wenn es seinen Teil erledigt hat (und die Programmteile des ursprünglichen Prozesses weiter abarbeitet), muss am Ende exit aufgerufen werden.
Wenn sich Kindprozesse beenden bleiben sie in Unix-Umgebungen zunächst im System, bis der Elternprozess diese wegräumt, indem er wait aufruft. wait wartet, bis ein Kindprozess gestorben ist und liefert dann die Prozess-ID dieses Kindes zurück. Falls es keine Kindprozesse gibt, kehrt wait sofort mit dem Rückgabewert -1 zurück.
Erzeugt ein Prozess viele Kinder so ist es am geschicktesten, die Zombies automatisiert abzuräumen. Dies lässt sich mit Hilfe eines Signalhandlers einrichten. Ein Signalhandler ist eine Funktion, die immer dann ausgeführt wird, wenn ein Signal eintrifft. Zu jedem Signal kann ein Prozess einen Signalhandler aufsetzen, der immer dann aufgerufen wird, wenn das Signal eintrifft. Um die Kinder automatisch abzuräumen muss ein Signalhandler für das Signal SIGCHLD installiert werden, der wait() aufruft:
sub sigchldHandler
{
wait();
$SIG{CHLD} = \&sigchldHandler;
}
Damit der Handler auch aufgerufen wird, muss er aufgesetzt werden. Bei Perl ist das aufsetzen von Signalhandlern sehr einfach: Eine Referenz auf die Funktion wird einfach zu dem entsprechenden Schlüssel, dem Signalnamen, in den Hash %SIG eingetragen. Sobald die Eintragung geschehen ist, wird der Signalhandler aufgerufen, wenn das entsprechende Signal ankommt. Ein Handler für SIGCHLD sollte also aufgesetzt werden, bevor Kindprozesse erzeugt werden! Für die Handlerfunktion sigchldHandler aus den obigen Beispielen sieht die Eintragung wie folgt aus:
$SIG{CHLD} = \&sigchldHandler;
Schreiben Sie ein Perl-Programm, das zu Beginn die Anzahl der zu erzeugenden
Kinder einliest, den Signalhandler installiert (wie oben beschrieben) und dann
entsprechend viele Kindprozesse erzeugt. print "Beenden? "; $input = <STDIN>Sie bewirken, dass es sich nicht beendet, solange Sie nichts eingeben. Dies gibt Ihnen Zeit, mit dem ps-Kommando zu überprüfen, ob die Kinder tatsächlich aufgeräumt wurden. Sobald Sie das Programm beenden, werden die von diesem Programm erzeugten Kinder vom System aufgeräumt und Sie können nicht mehr feststellen, ob der Signalhandler korrekt funktioniert hat.
Es gibt viele Rechner, die Webcam-Bilder erzeugen. Einige Beispiele dafür sind:
Marienplatz in Müchen
(http://blog.muenchen.de/marienplatzcam/marienplatzgross001.jpg)
Hof des Deutschen Museums
(http://www.deutsches-museum.de/fileadmin/Content/data/webcam/mushof_f.jpg)
Isar in München
(www.wwa-webcams.de/m/isar-plan/isar-plan.jpg)
Allianz-Arena
(webcam.allianz-arena.de/aa-cam-01/full_2.jpg)
Zugspitze
(http://cms.zugspitze.de/static/webcams/k04.jpg)
Mit dem Perl-Modul LWP::Simple ist es möglich, innerhalb eines Programms mit dem Befehl getstore $url, $file; eine durch $url spezifizierte Datei von einem fernen Server zu holen und unter dem Dateinamen $file (ggf. mit Pfadangabe im Dateinamen) auf dem lokalen Rechner abzuspeichern. Ein Programmfragment sieht dann etwa folgendermaßen aus:
#!/usr/bin/perl use LWP::Simple; . . . getstore $url, $file; . . .Schreiben Sie ein Perl-Programm, das ein Bild von einer beliebigen Webcam holt und lokal abspeichert. Dabei sollen rotierend immer 4 Bilder (b1.jpg - b4.jpg) zur Verfügung stehen, wobei immer b1.jpg das älteste und b4.jpg das jüngste Bild ist. Die Bilder müssen in der "Document-Root" des Servers abgelegt werden. Da das Script kein CGI-Script ist, sollte es sich in Ihrem Heimatverzeichnis befinden.
Hinweise:
rename($oldname, $newname) or warn "Couldn't rename $oldname to $newname: $!\n";
unlink($filename) or warn "Couldn't unlink $filename: $!\n";
Erzeugen Sie eine einfache HTML-Seite (ebenfalls in der "Document-Root" des Servers), in der alle 4 Bilder untereinander dargestellt werden und testen Sie damit die Funktion Ihres Programms.
Erzeugen Sie einen crontab-Eintrag für den zweiminütigen Aufruf des Programms der vorhergehenden Aufgabe und testen Sie die Funktion des Gesamtsystems.
| crontab datei | Fügt die Jobs in datei zur Crontab Datei des Benutzers hinzu. |
| crontab -r | Löscht die Crontab-Datei des Benutzers. |
| crontab -l | Listet die Jobs des Benutzers auf. |
| crontab -e | Erlaubt das Editieren der Crontab-Datei. |
Ein einzelner Job wird durch eine Zeile definiert, die das Zeitintervall und das genaue Kommando vorgibt. Die einzelnen Felder in der Datei sind durch Leerzeichen oder durch einen Tabulator getrennt. Da beim Aufruf eines Programms per crontab-Kommando der gesetzte Pfad (Variable PATH) nicht bekannt ist, sollten Sie alle Programme mit absolutem Pfad angeben.
| Minute | Stunde | Tag | Monat | Wochentag | Kommando |
| 0-59 | 0-23 | 1-31 | 1-12 | 0-6 | .... |
Bei der Angabe der Zeit sind einzelne Zahlen, Intervalle (z.B.: 3-8), Aufzählungen (z.B.: 1,3,5), sowie "*" für alle, möglich.
Beispiel: Die folgenden Zeilen definieren zwei Jobs:
# mm hh DoM MM DoW command # 30 * * * * /bin/foo 30 23 * * * /bin/bar > /dev/null 2>&1
Immer wenn der Minutenzeiger auf 30 steht wird das Programm /bin/foo gestartet. Und um 23:20 wird der Befehl /bin/bar ausgeführt. Dabei werden alle Ausgaben des Befehls ins Nirvana umgeleitet. Weitere Informationen können Sie mit dem Kommando man crontab abrufen.
Denken Sie daran, Ihren crontab-Eintrag zum Praktikumsende wieder zu deaktivieren, indem Sie mit crontab -e den Editor aufrufen und vor alle Zeilen ein Kommentarzeichen (#) setzen.
Dann können Sie im folgenden Termin die crontab-Einträge wieder schnell aktivieren, indem Sie das Kommentarzeichen löschen.
Damit sich die einzelnen Berabeitungsgruppen nicht gegenseitig behindern, müssen zu Beginn des Praktikums die Portnummern für jede Gruppe vergeben werden:
| Port | Rechner | Port | Rechner |
|---|---|---|---|
| 1201 | Merkur | 1202 | Venus |
| 1203 | Erde | 1204 | Mars |
| 1205 | Jupiter | 1206 | Saturn |
| 1207 | Uranus | 1208 | Neptun |
| 1209 | Pluto | 1210 | Ceres |
| 1211 | Eris | 1212 | Juno |
| 1213 | Pallas | 1214 | Vesta |
| 1215 | Xena |
In dieser Aufgabe sind ein Server und ein passender Client zu programmieren. Beginnen Sie mit dem Server und testen Sie diesen mit Hilfe des telnet-Programms. Schreiben Sie dann den zugehörigen Client. Server und Client können auf ein und demselben System programmiert werden, indem "localhost" als Server und Client dient. Auch die hardwarespezifischen Aktionen, die später auf einem Raspberry Pi ablaufen sollen, lassen sich weitgehend simulieren. Wenn Die Simulation läuft, kann einer der Raspberryies als Server dienen, indem Sie Ihre Server-Software hochladen.
Die Koordination der Gruppen erfolgt zum jeweiligen Praktikumstermin. Dabei arbeiten immer zwei Gruppen miteinander: eine Gruppe schreibt den Client, die andere den Server. Auch die Login-Daten für die Raspberry Pi Systeme erfahren Sie im Praktikum.
Die Namen und IP-Adressen der Raspberry-Systeme sind:
| Rechner | IP-Adresse |
|---|---|
| chiron | 10.27.210.230 |
| pholus | 10.27.210.231 |
| nessus | 10.27.210.232 |
Damit nicht jeder die Systeme ansprechen kann, wird zuerst ein Passwort abgefragt. Damit ergibt sich der im Folgenden skizzierte Dialog zwischen Client und Server:
| Client | Server |
|---|---|
| [Verbindungsaufnahme] | Rechnername, nice to meet you PASS |
| [Passwort] | falls Passwort akzeptiert wird: ACK sonst: NAK [Verbindungsabbruch] |
| [Kommando] | [ACK/NAK (ggf. Daten zum Kommando)] |
Die letzte Zeile kann sich beliebig oft wiederholen. Als Kommandos des Client sond möglich:
| Kommando | Gewünschte Daten |
|---|---|
| WHO | Ausgabe der Kommandos: hostname uname -or uptime |
| GET n | Wert des GPIO-Pins n |
| SET n [0|1] | Setzen des GPIO-Pins n auf 0 oder 1 |
| QUIT | "Bye" [Beenden der Verbindung] |
Der Server soll seine Aktivitäten auf dem Bildschirm protokollieren, indem er bei Verbindungsaufnahme die Client-IP ausgibt (print "Anfrage von ", $client->peerhost(), ":", $client->peerport(), "\n";) und dann den Dialog anzeigt.
Schreiben Sie nun einen Client, der eine Verbindung zum Server aufbaut, sich authentisiert und dann abhüngig von der Kommandozeilenoption eines oder mehrere der oben aufgeführten Abfragekommandos ausführt. Als Kommandozeilenoptionen kommen beliebige Kombinationen von -g (GET) -s (SET) und -w (WHO) in Frage. Danach beendet die Client die Verbindung (QUIT).
Die drei Systeme haben an vier GPIO-Ports eine Vierfarb-Power-LED angeschlossen, deren einzelne LEDs per GET- oder SET-Befehl ein- und ausgeschaltet werden können:
| GPIO22 | GPIO23 | GPIO24 | GPIO25 |
|---|---|---|---|
| ROT | GRUEN | BLAU | WEISS |
Für die Client- und Serverprogramme gilt: Das Passwort, die Portnummer(n) und die Serveradresse werden fest im Programm als Konstante verankert. zum Beispiel:
# --------------- Konfiguration -------------------- use constant PASSWD => "lassmichrein"; use constant MYPORT => 6666; use constant SERVER => "nessus"; # nur beim Client # --------------- Konfiguration --------------------
<html> <head></head> <body> <h1>Es geht!</h1> <p>Dies ist die Default-Webseite. Fehlt noch die Info!</p> </body></html>
#!/usr/bin/perl # # CGI response header print "Content-type: text/html\n\n" ; # HTML response page $| = 1; print qq~ <html> <head></head> <body> <h1>Hello</h1> <p>Dies ist das Default-Script.</p> </body> </html> ~; exit;
Denken Sie auch daran, dass die Ausgabe des CGI-Programms eine korrekte HTML-Seite ergeben muss. Das HTML-Formular für die Benutzereingaben befindet sich zunächst in einer getrennten Datei. Das Formular verwendet die HTTP-Methode POST zur Datenübermittlung. Das Feld "Port-Status" im Formular veranlasst den Client, alle vier GPIO-Ports abzufragen und deren Stand komplett zurück zu melden. Installieren Sie Formular und CGI-Programm auf einem der lc-Server.
Das Formular zur Aufgabe (Achtung: Bei "action" den Pfad ergänzen/ändern → USER, Programmname!):
<form action="http://lc1/~USER/cgi-bin/prakt.pl" method="post">
<table border="1" cellpadding="3" cellspacing="0" bgcolor="#CCCCCC">
<tr>
<td bgcolor="#EEFF99" valign="top">SET GPIO 22</td>
<td bgcolor="#EEFF99" valign="top">
<input type="radio" name="GPIO22" value="1">On
<input type="radio" name="GPIO22" value="0">Off </td>
</tr><tr>
<td bgcolor="#EEFF99" valign="top">SET GPIO 23</td>
<td bgcolor="#EEFF99" valign="top">
<input type="radio" name="GPIO23" value="1">On
<input type="radio" name="GPIO23" value="0">Off </td>
</tr><tr>
<td bgcolor="#EEFF99" valign="top">SET GPIO 24</td>
<td bgcolor="#EEFF99" valign="top">
<input type="radio" name="GPIO24" value="1">On
<input type="radio" name="GPIO24" value="0">Off </td>
</tr><tr>
<td bgcolor="#EEFF99" valign="top">SET GPIO 25</td>
<td bgcolor="#EEFF99" valign="top">
<input type="radio" name="GPIO25" value="1">On
<input type="radio" name="GPIO25" value="0">Off </td>
</tr><tr>
<td bgcolor="#EEEEEE" valign="top">Who</td>
<td bgcolor="#EEEEEE" valign="top">
<input type="radio" name="WHO" value="-">
</tr><tr>
<td bgcolor="#EEEEEE" valign="top">Port-Status</td>
<td bgcolor="#EEEEEE" valign="top">
<input type="radio" name="STAT" value="-">
</tr><tr>
<td bgcolor="#FF6666" valign="top">Passwort:
<input type="password" name="PASS" length="10"></td>
<td bgcolor="#FF6666" valign="top">
<input type="submit" value=" Absenden "></td>
</tr>
</table>
</form>
Optisch stellt sich das Formular dann folgendermaßen dar:
Beachten Sie, daß das Formular noch in eine korrekte HTML-Seite eingebettet werden muß.
Ziel dieser Praktikumsaufgabe ist die Realisierung eines Forums mithilfe von CGI-Scripten. Es ist sicher nicht sinnvoll, die gesamte Funktionalität auf eine einzige Seite zu packen. Überlegen Sie sich eine Struktur von Seiten (und auch die Links dazwischen), die folgende Aufgaben erfüllen sollen:
Es soll eine MySQL-Datenbank entwickelt werden, welche die Daten des Schwarzen Bretts speichert. Konzipieren Sie eine Tabelle inklusive der benötigten Datentypen und entwerfen Sie eine "CREATE TABLE"-Anweisunge für diese Tabelle. Hierbei müssen sich alle Teilnehmer auf eine Tabellenbeschreibung einigen, da diese Tabelle auch gemeinsam genutzt wird. Die Tabelle wird daher gemeinsam im Praktikum erstellt. Denken Sie auch daran, dass ein Timestamp-Feld vorgesehen werden muss.
Erstellen Sie das Web-Interface als CGI-Script in Perl. Es gibt zwei Möglichkeiten:
Überlegen Sie, wie Sie ein "Blättern" in der Ausgabe erreichen können (erst Beitrag 1 - 20, dann 21 -40 usw.). An die Implementierung gehen Sie erst, wenn die Suche (siehe unten) funktioniert.
Erstellen Sie ein einfache Suchformular für Datenbankabfragen. Abgefragt werden können (Teil-)-Strings Autor, Titel und natürlich Stichworte. Alternativ wird angegeben wie "alt" der Beitrag sein darf. Orientieren Sie sich bei der Ergebnis-Ausgabe am Output diverser Suchmaschinen: Fundstelle als Link (Titel), darunter Autor und Erstellungsdatum.
Versuchen Sie dann, logische Verknüpfungen der Suchanfrage zu realisieren und überlegen Sie, wie man ein Ranking der Suchergebnisse gestalten könnte. Lassen sich Eingabe, Ausgabe und Suche in einem Script vereinigen (Stichwort: State-Machine)?