Von C nach Java, Teil 3: HTML-Dokumente aus dem Internet laden

HTML-Dokumente unter C von einem Webserver zu holen, kann mitunter recht aufwändig sein. Ein Vergleich verschiedener Implementierungen zeigt, dass der Entwickler mit mit Java schneller ans Ziel kommt.

In Pocket speichern vorlesen Druckansicht 84 Kommentare lesen
Lesezeit: 24 Min.
Von
  • Andreas Nieden
Inhaltsverzeichnis

HTML-Dokumente unter C von einem Webserver zu holen, kann mitunter recht aufwändig sein. Ein Vergleich verschiedener Implementierungen zeigt, dass der Entwickler mit mit Java schneller ans Ziel kommt.

Das Auslesen von HTML-Dokumenten wie News-Seiten aus dem Netz ist ein gängiger Anwendungsfall, dementsprechend gibt es verschiedene Mechanismen für den Zugriff auf einen Webserver. Schaut man sich die Sprache C an, wird jedoch deutlich, dass so ein Zugriff von den Schöpfern der Sprache ursprünglich nicht vorgesehen war. Prinzipiell kann ein Entwickler zwischen einer komplett eigenen Lösung auf Grundlage der Socket Library wählen, oder er muss auf diverse Bibliotheken zurückgreifen. Das kann mitunter aufwändig sein – mit Java geht es etwas einfacher.

Mehr Infos

Quellcode zum Artikel

Die im Artikel gezeigten Programmbeispiele finden Sie auf dem FTP-Server von heise Developer zum Download (.zip, 15 KByte).

Im Beispiel greift ein C-Programm über die Socket Library auf den URL http://www.spiegel.de/schlagzeilen zu. Dafür ist ein ungefilterter Zugriff auf das Web notwendig, es dürfen keine Proxy-Server zwischen dem Client-PC und dem Internet liegen, und eine direkte Verbindung zum abzufragenden Host muss möglich sein. Schließlich baut das Programm eine TCP-Verbindung über den HTTP-Port 80 zum Server auf und fragt das gewünschte HTML-Dokument ab. Stark vereinfacht lässt sich der Vorgang sogar über eine Telnet-Session realisieren:

C:\> telnet www.spiegel.de 80
GET http://www.spiegel.de/schlagzeilen/ HTTP/1.0

Nach einer kurzen Wartezeit füllt sich der Bildschirm mit dem unformatierten HTML-Code, der unter anderem die aktuellen Schlagzeilen beinhaltet.

Jetzt soll die Frage geklärt werden, wie sich das Ganze mit einem C-Programm bewerkstelligen lässt, wenn zunächst ausschließlich die Socket Library für die Umsetzung des TCP-Protokolls zu verwenden ist. Dabei soll das Programm als Argument einen URL (Uniform Resource Locator) annehmen, um das Ganze etwas universeller zu gestalten.

Mehr Infos

Alle Artikel der Reihe

In dieser Artikelserie bereits erschienen:

  • Teil 1: Der schnelle Umstieg von der Kommandozeile aus
  • Teil 2: Files, I/O und eine Entwicklungsumgebung
  • Teil 3: HTML-Dokumente aus dem Internet laden
  • Teil 4: Datenkompression und Verschlüsselung
  • Teil 5: Wie eine grafische Oberfläche entsteht

Der Ausdruck http://www.spiegel.de/schlagzeilen/ ist eine solcher URL, dessen Bestandteile das Protokoll (http), der Hostname (www.spiegel.de) und der Pfad (schlagzeilen/) des zu ladenden Dokuments sind. Protokoll und Hostnamen werden vom String :// getrennt, während ein Slash den Hostnamen vom aufzurufenden Dokument trennt. Die Socket-Bibliothek von Windows stellt mit CrackURL() eine passende Funktion zur Verfügung, die den URL in seine Bestandteile zerlegt. Unter Unix gibt es für C leider kein passendes Pendant in der Socket-Bibliothek.

Am Anfang steht der Aufbau einer TCP-Verbindung zum Webserver auf dem HTTP-Port 80. Dazu dient die Socket-Funktion connect(), wobei die hier zu übergebenden Parameter alles andere als einfach sind. Neben dem Socket-Deskriptor (vergleichbar mit einem Filedeskriptor), ist eine gefüllte sockaddr-Struktur zu übergeben, die den Typ der Verbindung, die IP-Adresse des Webservers und den gewünschten Zielport bereitstellt. Diese Informationen muss das Programm vor dem Aufruf von connect() bereitstellen. Den Rest setzt der sogenannte RFC 2616 (Request for Comment), der das HTTP-Protokoll beschreibt, rudimentär im Programm um.

Es sei an dieser Stelle nochmals darauf hingewiesen, dass die in dieser Reihe verwendeten Techniken ausschließlich auf das Programmbeispiel zugeschnitten sind. Allein für die komplette Umsetzung des RFC 2616 wären viele Seiten Quelltext notwendig, was den Rahmen dieses Beitrags vollends sprengen würde. Daher wird beim Return Code lediglich geprüft, ob ein Code >= 400 vorliegt, der in der Regel eine Fehlersituation beschreibt, oder ob die Codes 301/302, die eine Umleitung anzeigen, zurückgeliefert werden. In diesem Fall muss im HTTP Header eine Sektion Location: mit einem neuen gültigen URL vorhanden sein, der im Anschluss geladen wird.

Jetzt zum kompletten Programm, mit detaillierten Erläuterungen. Das entsprechende Java-Pendant im Anschluss zeigt, wie viel an Aufwand dem Entwickler allein durch die Socket-Implementierung von Java abgenommen wird und um wie viel kürzer sich der Quelltext halten lässt.

Zunächst ein Blick in den Header der getURL.c (für das Einbinden der Headerfiles, Prototyping und Setzen der globalen Variablen):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#include <winsock.h>
#else
#include <netdb.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#endif

#define BUFFER_SZ 1024*1024

int Connect(char *, int);
int crackURL(char *, char *, char *);
int ReceiveHtmlDocument(char *, char *, int *);
int receiveLine(int, char *, int);
void usage();

char appName[]="getURL";

Im ersten Teil sind die einzubindenden Headerfiles zu finden, wobei hier zwischen Windows und Unix-Umgebungen unterschieden wird. Bei den hier verwendeten Beispielen kommt der GNU C-Compiler zum Einsatz, der auf Windows-Umgebungen zum Beispiel über das frei erhältliche "MinGW"-Paket erhältlich ist.

Übersetzt wird das komplette Beispiel unter Unix mit

$ gcc –s –o getURL getURL.c

und unter Windows mit

C:\>gcc –s –DWIN32 –o getURL.exe getURL.c –lwsock32

Während unter vielen Unix-Implementierungen die Socket Library automatisch gelinkt wird, muss man sie unter Windows explizit mit angeben (-lwock32). Die Option -s entfernt die Verweise aus der Binary, -o gibt den Dateinamen des ausführbaren Programms an (standardmäßig a.out) und -DWIN32 setzt das Flag WIN32 im Quellcode, in dem das Programm mittels der Präprozessorabfrage (#ifdef ... #else ... #endif) entsprechend den Source für die richtige Plattform auswählt.