Netzwerk
TCP/IP (Webserver)
3 Funktionen für die Netzwerkprogrammierung

Im folgenden werden einige C Funktionen aufgeführt, mit denen man eine Netzwerkkommunikation herstellen kann.

 


3.1 Byteanordnung

Um Zahlen von der lokal verwendeten Byte-Reihenfolge (host byte order) in die TCP/IP Byte-Reihenfolge (network byte order) zu konvertieren, steht die Funktion

 

#include <netinet/in.h>

unsigned long int htonl ( unsigned long int hostlong); [return: die network byte order zum long-Wert „hostlong“, der in host byte order übergeben wird]
unsigned long int ntohl ( unsigned long int netlong) [return: die host byte order zum long-Wert „netlong“, der in network byte order übergeben wird]
unsigned short int htons ( unsigned short int hostshort );
unsigned short int ntohs ( unsigned short int netshort );

3.2 IP Adressen

Hier sind Funktionen aufgeführt, die zur Manipulation, Konvertierung und zum Extrahieren von IP Adressen benutzt werden.

 

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

int inet_aton ( const char *cp, struct in_addr *inp); [return: =0 Fehler; != OK]

 

Konvertiert die übergebene IP Adresse von der gepunkteten Dezimaldarstellung in einen numerischen Wert, den sie im Speicherplatz hinterlegt, auf den inp zeigt.

 

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

unsigned long int inet_addr ( const char *cp);

 

Dies ist eine veraltete Funktion. Diese hat die Nachteile, das sie das Ergebnis der Konvertierung als Returnwert zurückgibt. Damit ist 255.255.255.255 und der Fehlercode –1 das selbe. Desweiteren liefert diese einen long-Wert, was ein unschönes casting notwendig macht.

 

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

char *inet_ntoa ( struct in_addr in);

 

Um eine IP Adresse von ihrem numerischen Wert in die punktierte Dezimaldarstellung zu konvertieren, wird diese Funktion angewendet.

 

Beachte: Der zurückgegebene String ist ein static-buffer, d.h. beim nächsten Aufruf wird dieser von der Funktion überschrieben.

 

Damit die Netzwerknummer aus der punktierten Dezimaldarstellung ermittelt werden kann, benutzt man die Funktion

 

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

unsigned long int inet_network ( const char *cp); [return: -1  Fehler]

 

Diese Funktion liefert die Netrzwerknummer in host byte order.

Zum extrahieren der Netzwerknummer aus der numerischen IP Adresse steht folgende Funktion zur Verfügung

 

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

unsigned long int inet_netof ( struct in_addr in);

 

Will man die numerische, lokale Rechernummer (Host Anteil) aus einer numerischen IP Adresse ermitteln, benutzt man

 

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

unsigned long int inet_lnaof ( struct in_addr in);

 

Die letzte Funktion ermittelt aus der Netzwerknummer (host byte order) und aus der lokalen Rechnernummer (host byte order) die vollständige numerische IP Adresse.

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

struct in_addr inet_makeaddr ( int net, int host);

3.3 Domain Name Service

Durch eine IP Adresse wird einem Rechner eine eindeutige Kennung zugewiesen. Da diese numerisch ist, kann man sich diese nicht gut merken. Aus diesem Grund wird i.d.R. jedem Rechner ein Name vergeben, der aus einem Host-Anteil und einem Domain-Anteil besteht. Host- und Domain-Anteil werden durch einen Punkt getrennt, wobei der Domain-Anteil selbst Punkte enthalten darf.

 

Beispiel:

www.google.de (Host: www, Domain: google.de)

one.subnet.domain.de (Host: one, Domain: subnet.domain.de)

 

Der Aufbau ist folgendermaßen

<Grafik>

 

Ein Nameserver ist für das Auflösen von Domain-Namen und IP Adressen zuständig. Normalerweise wird der komplette Rechnername übermittelt und die zugehörige IP Adresse wird zurückgegeben. Der andere Weg (IP zu Domainnname) nennt man Reverse-Lookup.

 

Bei kleineren Netzwerken wird diese Auflösung über die hosts-Datei gemacht. Bei großen Netzwerken wird ein Service diese Auflösung übernehmen (Domain Name Service, DNS).

 

Beim Suchen schaut der DNS in seinen eigenen Daten. Findet er die benötigte Information nicht, kontaktiert er seinerseits andere DNS. Finden diese auch nichts, so gibt der kontaktierte DNS eine „not found“ Meldung zurück. Dem Anfragenden steht es frei, weitere DNS zu befragen.

 

Anmerkung: Somit ist auch klar, das zu einer Internetverbindung (z.B. T-.Online, AOL, ...) mindestens eine feste IP Adresse angegeben werden muss. Alle anderen Rechner können über deren Namen von einem DNS aufgelöst werden.

 

Für die folgenden Funktionen ist die Struktur hostent wichtig

 

struct hostent

{

 char *h_name;  // offizieller Name

 char **h_aliases;  // Aliasliste (Stringarray mit NULL-

     // Zeiger am Ende)

 int h_addrtype;  // Host-Adresstyp (AF_INET bei IPv4)

 int h_length;  // Länge der Adresse

     // =sizeof (struct in_addr)

 char **h_addr_list; // Liste von Adressen von Namen (Array

     // von Zeigern auf die Adressen für

     // diesen Rechner)

}

 

Folgende Funktionen geben Informationen zum Rechner

 

#include <netdb.h>

#include <sys/socket.h>

struct hostent *gethostbyname ( const char *name);
struct hostent *gethostbyaddr ( const char *addr, int len, int type);

 

Die erste Funktion liefert die hostent-Einträge für den Rechnernamen. Bei der zweiten Funktion werden die hostent-Einträge für die IP Adresse geliefert.

Tritt ein Fehler auf, so wird die globale Fehlervariable h_errno gesetzt und kann mit

 

void herrno ( const char *s)

 

ausgegeben werden. Hierbei ist s ein Zusatztext.

 


3.4 Portnummern

Oben haben wir die Portnummern bereits angesprochen. Der Standard schreibt viele Portnummern vor, die die Internet Assigned Number Authority (IANA) verwaltet. Die Portnummern und die zugehörigen Dienste (und damit die Protokolle) sind in der services-Datei hinterlegt.

 

Informationen über die Ports und die Dienste werden in der Struktur

struct servent

{

 char *s_name;  // offizieller Name

 char **s_aliases;  // Aliasliste

 int s_port;   // Port Nummer

 char *s_proto;  // zu verwendendes Protokoll

}

zur Verfügung gestellt.

 

Informationen über die einzelnen Dienste erhält man über die Funktionen

struct servent *getservbyname ( const char *name, const char proto);
struct servent *getservbyport ( int port, conmst char *proto);

 

Diese liefern einen Zeiger auf die servent-Struktur des Rechners, ein NULL bei Mißerfolg.

 

Anmerkung: Der Speicher ist ein static-buffer. Bei einem erneuten Aufruf dieser Funktionen wird dieser intern überschrieben

 

Im Fehlerfalle wird die globale Fehlervariable h_errno gesetzt.

Um die services-Datei zu durchlaufen, stehen die drei Funktionen

struct servent *getservent ( void );
void setservent ( int stayopen );
void endservent ( void );

zur Verfügung.

 

Mit setservent() wird die services-datei geöffnet. stayopen = TRUE (!=0) bewirkt, das die Datei bei den folgenden Funktionsaufrufen nicht geschlossen wird. Bei stayopen = FALSE (=0) wird die Datei nach dem nächsten Funktionsaufruf geschlossen.

 

Die Funktion getservent() liefert den aktuellen Eintrag und positioniert den Lesezeiger einen Eintrag weiter. Mit endservent() wird die Datei wieder geschlossen.

 

Anmerkung: Man sollte auf die services-datei mit diesen Funktionen zugreifen und nicht mit fopen(), da diese Funktionen einen kontrollierten Zugriff gewährleisten.

 



Last update:  13.07.2005