Open Source im professionellen Einsatz
Linux-Magazin 11/2007
585

HTTP-Server weg

Nachdem aus LAMP nun das M und das P verschwunden sind, muss konsequenterweise noch das A folgen, nämlich der HTTP-Server Apache. Bei LOA ist er ein Bestandteil des Serverprozesses. Dessen Implementierung für die Tauschzone ist überraschend schlank ausgefallen, obwohl alle wichtigen Komponenten vorhanden sind.

Der HTTP-Server (Klasse »HTTPServer«) hört auf TCP-Port 80 und verteilt Anfragen (also durch »accept(2)« erhaltene Verbindungssockets) an einen Pool von Threads der Klasse »ClientConnection«. Jeder wartet, bis er vom Server die nächste Verbindung zugeteilt bekommt, holt dann geduldig die HTTP-Anfrage vom Browser auf der anderen Seite des Netzes und bereitet sie in Form eines Objekts vom Typ »HTTPRequest« auf. Der Pseudocode aus Listing 3 skizziert die Implementierung.

Listing 3:
HTTP-Server

01 // Hauptschleife von Webserver
02 HTTPServer::serve()
03 {
04     // Threads für die Verbindungen erzeugen
05     for (int i=0; i<NUM_THREADS; i++) {
06         createClientThread();
07     }
08 
09     int s = openTCPSocket(80); // auf Port 80 hören
10     int client;
11     while (true)
12     {
13         // Systemcall accept() wartet auf nächste Clientverbindung
14         client = accept(s);
15         // Filedescriptor in Warteschlange stopfen
16         pushConnection(client);
17     }
18 }
19 
20 
21 // Hauptschleife von Thread
22 ClientConnection::run()
23 {
24     while (!should_terminate)
25     {
26         // nächste Clientverbindung aus Warteschlange holen
27         // (blockiert, solange Warteschlange leer ist)
28         int fd = server->getConnection();
29 
30         // HTTP Header von Socket lesen und parsen
31         HTTPRequest request(fd);
32 
33         // HTML Objekt erzeugen zum Speichern des Ergebnisses
34         HTML html;
35 
36         // Seite von Engine berechnen lassen
37         engine->processRequest(request, html);
38 
39         // Ergebnis an Client zurückschreiben
40         writeHTTPHeader(request, fd);
41         write(fd, html.buffer(), html.length();
42 
43         // Verbindung zum Client schließen
44         close(fd);
45     }
46 }

Nach dem Empfangen kann die Engine den Request bearbeiten. Sie ist gewissermaßen Datenbank und Seitengenerator in einem. Sie generiert HTML-Code in Form eines Objekts vom Typ »HTML«, das einen Puffer für die Aufnahme des HTML-Code kapselt. Ist die Engine fertig, kann der Thread das Ergebnis in einem Rutsch an den Browser zurücksenden. Damit es keine Probleme mit der Datenkonsistenz gibt, darf allerdings immer nur ein Thread gleichzeitig die Engine benutzen.

Schneller als SQL

Listing 4 zeigt, wie die Engine anhand von Bestandteilen der URL in verschiedene Funktionen verzweigt, die jeweils eine Art Seite generieren. Das Beispiel der Artikelseite (Funktion »pageArticle«) demonstriert, wie sich der Artikel anhand seiner ID im Index »articleById« auffinden lässt. Danach stehen alle Daten des Artikels direkt über das Objekt »art« zur Verfügung.

Listing 4: Seitengenerierung
durch die Engine

01 Engine::processRequest(HTTPRequest &request, HTML &html)
02 {
03     // Dafür sorgen, dass nur ein Thread die Engine
04     // betritt (hier mit pthread-Mechanismen gelöst)
05     pthread_mutex_lock(&_mutex);
06 
07     // Kein Verzeichnis -> index.html
08     if (request.numDirs() == 0)
09         pageIndex(request, html);
10 
11     // 1. Pfadkomponente unterscheidet Art der Seite
12     else if (!strcmp(request.dir(0), "art"))
13         pageArticle(request, html); // Artikelseite
14 
15     else if (!strcmp(request.dir(0), "search"))
16         pageSearch(request, html); // Suchabfrage
17 
18     else
19         pageUnknown(request, html); // Unbekannte Seite
20 
21     // Zugang zur Engine wieder freigeben
22     pthread_mutex_unlock(&_mutex);
23 }
24 
25 
26 // Artikelseite, exemplarisch
27 Engine::pageArticle(HTTPRequest &request, HTML &html)
28 {
29     // Artikelnummer ist 2. Pfadkomponente, z.B. /art/1829/
30     int artid = atoi(request.dir(1));
31 
32     // Finde Artikel in Suchindex
33     Article *art = articleById(artid);
34     if (art) {
35         // HTML-Kopf mit Seitentitel erzeugen
36         html.addPageHeader(art->title()); // Titel des Artikels
37 
38         // Inhalt der Seite anhand der Daten aus dem Objekt art
39         html.add("Beschreibung: %s<br>n", art->description());
40         html.add("Anbieter: %s<br>n",     art->owner->fullname());
41 
42         // Seitenfuss und HTML-Abschlusscode
43         html.addPageFooter();
44     }
45     else // Artikel nicht gefunden
46         pageUnknown(request, html);
47 }

Das ist nicht nur einfacher und übersichtlicher als bei der Programmierung mit einer SQL-Datenbank, sondern auch um Größenordnungen schneller. Tabelle 1 beweist mit den verwendeten C++-Klassen die überschaubare Komplexität der HTTP-Implementierung.

Tabelle 1:
Code-Umfang

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 5 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • Meteor

    Javascript sowohl im Browser als auch auf dem Server: Das Webframework Meteor verspricht Anwendungen aus einem Guss, die sich dank vieler fertiger Pakete rasch programmieren lassen.

  • Backbone.js

    Die Javascript-Engines moderner Browser sind leistungsfähig genug, um die Anwendungslogik zu übernehmen. Wie auf dem Server beschleunigen auch hier Frameworks die Entwicklung. Ein herausragendes Beispiel für diese Gattung ist Backbone.js, das ein lokales Datenmodell umsetzt.

  • Gesichert wie eine Bank

    Die beliebte Open-Source-Datenbank MySQL kennt verschiedene Möglichkeiten der Datensicherung. Jede hat Vor- und Nachteile, die jedoch nur unter bestimmten Umständen gravierend sind.

  • Django

    Alle befragten Django-Entwickler waren über die vom Linux-Magazin gestellte Aufgabe nicht glücklich: Mit einem CMS sei das wesentlich einfacher zu lösen, hieß es. Autor Sven Schannak zeigt, wie es trotzdem klappt.

  • Perl-Snapshot

    Größere Dateien tauscht die Jugend heute gerne über den proprietären Dropbox-Service aus. Dessen Web-API erlaubt auch den Einsatz selbst geschriebener Skripte, beispielsweise zum Abholen einer Datei aus dem Schatten einer Firewall.

comments powered by Disqus

Stellenmarkt

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.