Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
Vorwort des Gutachters
1 Einstieg in C
2 Das erste Programm
3 Grundlagen
4 Formatierte Ein-/Ausgabe mit »scanf()« und »printf()«
5 Basisdatentypen
6 Operatoren
7 Typumwandlung
8 Kontrollstrukturen
9 Funktionen
10 Präprozessor-Direktiven
11 Arrays
12 Zeiger (Pointer)
13 Kommandozeilenargumente
14 Dynamische Speicherverwaltung
15 Strukturen
16 Ein-/Ausgabe-Funktionen
17 Attribute von Dateien und das Arbeiten mit Verzeichnissen (nicht ANSI C)
18 Arbeiten mit variabel langen Argumentlisten – <stdarg.h>
19 Zeitroutinen
20 Weitere Headerdateien und ihre Funktionen (ANSI C)
21 Dynamische Datenstrukturen
22 Algorithmen
23 CGI mit C
24 MySQL und C
25 Netzwerkprogrammierung und Cross–Plattform-Entwicklung
26 Paralleles Rechnen
27 Sicheres Programmieren
28 Wie geht’s jetzt weiter?
A Operatoren
B Die C-Standard-Bibliothek
Stichwort

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
C von A bis Z von Jürgen Wolf
Das umfassende Handbuch
Buch: C von A bis Z

C von A bis Z
3., aktualisierte und erweiterte Auflage, geb., mit CD und Referenzkarte
1.190 S., 39,90 Euro
Rheinwerk Computing
ISBN 978-3-8362-1411-7
Pfeil 25 Netzwerkprogrammierung und Cross–Plattform-Entwicklung
Pfeil 25.1 Begriffe zur Netzwerktechnik
Pfeil 25.1.1 IP-Nummern
Pfeil 25.1.2 Portnummer
Pfeil 25.1.3 Host- und Domainname
Pfeil 25.1.4 Nameserver
Pfeil 25.1.5 Das IP-Protokoll
Pfeil 25.1.6 TCP und UDP
Pfeil 25.1.7 Was sind Sockets?
Pfeil 25.2 Headerdateien zur Socketprogrammierung
Pfeil 25.2.1 Linux/UNIX
Pfeil 25.2.2 Windows
Pfeil 25.3 Client/Server-Prinzip
Pfeil 25.3.1 Loopback-Interface
Pfeil 25.4 Erstellen einer Client-Anwendung
Pfeil 25.4.1 »socket()« – Erzeugen eines Kommunikationsendpunktes
Pfeil 25.4.2 »connect()« – ein Client stellt eine Verbindung zum Server her
Pfeil 25.4.3 Senden und Empfangen von Daten
Pfeil 25.4.4 »close()« und »closesocket()«
Pfeil 25.5 Erstellen einer Server-Anwendung
Pfeil 25.5.1 »bind()« – Festlegen einer Adresse aus dem Namensraum
Pfeil 25.5.2 »listen()« – Warteschlange für eingehende Verbindungen einrichten
Pfeil 25.5.3 »accept()« und die Serverhauptschleife
Pfeil 25.6 (Cross-Plattform-)TCP-Echo-Server
Pfeil 25.6.1 Der Client
Pfeil 25.6.2 Der Server
Pfeil 25.7 Cross-Plattform-Development
Pfeil 25.7.1 Abstraction Layer
Pfeil 25.7.2 Headerdatei für Linux/UNIX
Pfeil 25.7.3 Linux/UNIX-Quellcodedatei
Pfeil 25.7.4 Headerdatei für MS-Windows
Pfeil 25.7.5 Windows-Quellcodedatei
Pfeil 25.7.6 All together – die »main«-Funktionen
Pfeil 25.7.7 Ein UDP-Beispiel
Pfeil 25.7.8 Mehrere Clients gleichzeitig behandeln
Pfeil 25.8 Weitere Anmerkungen zur Netzwerkprogrammierung
Pfeil 25.8.1 Das Datenformat
Pfeil 25.8.2 Der Puffer
Pfeil 25.8.3 Portabilität
Pfeil 25.8.4 Von IPv4 nach IPv6
Pfeil 25.8.5 RFC-Dokumente (Request for Comments)
Pfeil 25.8.6 Sicherheit


Rheinwerk Computing - Zum Seitenanfang

25.5 Erstellen einer Server-Anwendung Zur nächsten ÜberschriftZur vorigen Überschrift

Eine Server-Anwendung zu erstellen ist nicht viel schwieriger als das Programmieren der Client-Anwendung. Der Datenaustausch erfolgt genauso wie bei der Client-Anwendung via send()/recv() (TCP) bzw. sendto()/recvfrom() (UDP). Der Server muss allerdings keine Verbindung herstellen – dies ist die Aufgabe des Clients. Allerdings ist es die Aufgabe des Servers, Verbindungswünsche anzunehmen. Und um dies zu realisieren, müssen Sie den Server in einen Wartezustand versetzen.


Rheinwerk Computing - Zum Seitenanfang

25.5.1 »bind()« – Festlegen einer Adresse aus dem Namensraum Zur nächsten ÜberschriftZur vorigen Überschrift

Nachdem Sie auch auf der Serverseite mit der Funktion socket() eine »Steckdose« bereitgestellt haben, müssen Sie zunächst die Portnummer der Server-Anwendung festlegen. Sie wissen ja bereits von der Clientanwendung, dass mittels connect() auf eine bestimmte IP-Adresse und eine Portnummer des Servers zugegriffen wird. Unter welcher IP-Adresse und Portnummer der Server nun auf Anfragen der Clients wartet, müssen Sie mit der Funktion bind() festlegen. Somit weisen Sie praktisch einem Socket eine Adresse zu – schließlich ist es durchaus gängig, dass eine Serveranwendung mehrere Sockets verwendet. Dass hierbei meistens die IP-Adresse die gleiche ist, dürfte klar sein, aber es ist durchaus möglich, die Datenübertragung über mehrere Ports zuzulassen. Die Funktion bind() wiederum teilt dem Betriebssystem mit, welchen Socket es mit einem bestimmten Port verknüpfen soll. Sobald dann ein Datenpaket eingeht, erkennt das Betriebssystem anhand der Portnummer, für welchen Socket das Paket ist.

Die Syntax zur Funktion bind() lautet bei Linux/UNIX:

#include <sys/types.h>
#include <sys/socket.h>

int bind( int s, const struct sockaddr name, int namelen );

Bei MS-Windows lautet die Syntax ähnlich:

#include <winsock.h>

int bind(SOCKET s, const struct sockaddr FAR* name, int namelen);

Als ersten Parameter übergeben Sie wie immer den Socket-Deskriptor, den Sie mit socket() angelegt haben. Mit dem zweiten Parameter geben Sie einen Zeiger auf eine Adresse und Portnummer an. Damit teilen Sie dem System mit, welche Datenpakete für welches Socket gedacht sind. Die Struktur sockaddr bzw. (einfacher) sockaddr_in und deren Mitglieder wurde bereits ausführlich im Abschnitt zur Funktion connect() beschrieben. Allerdings sollte hier noch erwähnt werden, dass ein Rechner häufig über verschiedene Rechner (unter mehreren Adressen) und auch verschiedenste Netze (Internet, Intranet, lokales Netzwerk etc.) erreichbar ist bzw. sein muss. Damit ein Server über alle Netze und IP-Adressen eine Verbindung annimmt, setzt man die IP-Adresse auf INADDR_ANY (natürlich in Network Byte Order). Ansonsten geben Sie die IP-Adresse wie gewöhnlich mit der Funktion inet_addr() an.

Es ist außerdem auch möglich, neben der IP-Adresse eine beliebige Portnummer zuzulassen. Hierfür müssen Sie lediglich 0 als Portnummer (in Network Byte Order) verwenden. Welchen Port Sie dann erhalten haben, können Sie mit der Funktion getsockname() im Nachhinein abfragen. Mehr zu dieser Funktion können Sie aus der entsprechenden Dokumentation entnehmen (beispielsweise der Manual-Page).

Mit dem letzten Parameter geben Sie wiederum die Länge der Struktur (zweiter Parameter) in Bytes mit sizeof() an. bind() liefert im Falle eines Fehlers –1 (gleichwertig mit dem Fehlercode SOCKET_ERROR unter MS-Windows). Welcher Fehler aufgetreten ist, können Sie wiederum mit errno (Linux/UNIX) bzw. WSAGetLastError() (MS-Windows) in Erfahrung bringen.

Hier sehen Sie einen kurzen Codeausschnitt, der zeigt, wie die Zuweisung einer Adresse auf der Serverseite in der Praxis realisiert wird:

struct sockaddr_in server;

memset( &server, 0, sizeof (server));
// IPv4-Adresse
server.sin_family = AF_INET;
// Jede IP-Adresse ist gültig
server.sin_addr.s_addr = htonl( INADDR_ANY );

// Portnummer 1234
server.sin_port = htons( 1234 );

if(bind( sock, (struct sockaddr*)&server, sizeof( server)) < 0) {
   //Fehler bei bind()
 }

Rheinwerk Computing - Zum Seitenanfang

25.5.2 »listen()« – Warteschlange für eingehende Verbindungen einrichten Zur nächsten ÜberschriftZur vorigen Überschrift

Im nächsten Schritt müssen Sie eine Warteschlange einrichten, die auf eingehende Verbindungswünsche eines Clients wartet – man spricht auch gerne vom »Horchen« auf Verbindungen, die am Socket eingehen. Eine solche Warteschlange wird mit der Funktion listen() eingerichtet. Dabei wird die Programmausführung des Servers so lange unterbrochen, bis ein Verbindungswunsch eintrifft. Mit listen() lassen sich durchaus mehrere Verbindungswünsche »gleichzeitig« einrichten. Die Syntax dieser Funktion sieht unter Linux/UNIX wie folgt aus:

#include <sys/types.h>
#include <sys/socket.h>

int listen( int s, int backlog );

Unter MS-Windows hingegen sieht die Syntax wie folgt aus:

#include <winsock.h>

int listen( SOCKET s, int backlog );

Mit dem ersten Parameter geben Sie wie immer den Socket-Deskriptor an und mit dem zweiten Parameter die Länge der Warteschlange. Die Länge der Warteschlange ist die maximale Anzahl von Verbindungsanfragen, die in eine Warteschlange gestellt werden, wenn keine Verbindungen mehr angenommen werden können.

Der Rückgabewert ist bei Erfolg 0 und auch hier bei einem Fehler –1 (gleichbedeutend unter MS-Windows mit SOCKET_ERROR). Den Fehlercode selbst können Sie wieder wie gehabt mit errno (Linux/UNIX) bzw. WSAGetLastError() (MS-Windows) auswerten.

In der Praxis sieht die Verwendung von listen() wie folgt aus:

if( listen( sock, 5 ) == -1 ) {
   // Fehler bei listen()
}

Rheinwerk Computing - Zum Seitenanfang

25.5.3 »accept()« und die Serverhauptschleife topZur vorigen Überschrift

Sobald nun ein oder mehrere Clients Verbindung mit dem Server aufnehmen wollen, können Sie sich darauf verlassen, dass die Funktion accept() immer die nächste Verbindung aus der Warteschlange holt (die Sie mit listen() eingerichtet haben). Hier sehen Sie die Syntax dazu unter Linux/UNIX:

#include <sys/types.h>
#include <sys/socket.h>

int accept( int s, struct sockaddr *addr, socklen_t addrlen );

Die Syntax unter MS-Windows ist ähnlich:

#include <winsock.h>

SOCKET accept( SOCKET s,
               struct sockaddr FAR* addr,
               int FAR* addrlen );

An der Syntax unter MS-Window lässt sich gleich erkennen, dass die Funktion accept() als Rückgabewert ein neues Socket zurückgibt. Hierbei handelt es sich um das gleiche Socket mit denselben Eigenschaften wie vom ersten Parameter s. Über dieses neue Socket wird anschließend die Datenübertragung der Verbindung abgewickelt. Ein so akzeptiertes Socket kann allerdings nicht mehr für weitere Verbindungen verwendet werden. Das Orginalsocket s hingegen bleibt weiterhin für weitere Verbindungswünsche offen.


Hinweis

accept() ist eine blockierende Funktion. Das heißt, accept() blockiert den aufrufenden (Server-)Prozess so lange, bis eine Verbindung vorhanden ist. Sofern Sie die Eigenschaften des Socket-Deskriptors auf nicht-blockierend ändern, gibt accept() einen Fehler zurück, wenn beim Aufruf keine Verbindungen vorhanden sind.


Mit dem zweiten Parameter schreibt accept() Informationen (IP-Adresse und Port) über den Verbindungspartner in die Struktur sockaddr bzw. sockaddr_in. Dies ist logischerweise nötig, damit Sie wissen, mit wem Sie es zu tun haben. addrlen wiederum ist die Größe der Struktur sockaddr bzw. sockaddr_in – allerdings wird diesmal ein Zeiger auf die Größe der Adresse erwartet!

Bei einem Fehler wird –1 (gleichbedeutend mit SOCKET_ERROR unter MS-Windows) zurückgegeben. Die genaue Ursache des Fehlers können Sie wieder mit errno (Linux/UNIX) bzw. WSAGetLastError() (MS-Windows) ermitteln. Bei erfolgreicher Ausführung von accept() wird, wie bereits beschrieben, ein neuer Socket-Deskriptor zurückgegeben.

Ein wichtiger Teil der Serverprogrammierung ist außerdem die Serverhauptschleife. In dieser Schleife wird gewöhnlich die Funktion accept() aufgerufen, und darin findet auch gewöhnlich der Datentransfer zwischen Client und Server statt. Hier sehen Sie ein Beispiel für eine solche Serverhauptschleife:

struct sockaddr_in client;
int sock, sock2;
socklen_t len;
...
for (;;) {
        len = sizeof( client );
        sock2 = accept( sock, (struct sockaddr*)&client, &len);
        if (sock2 < 0) {
            //Fehler bei accept()
        }
        // Hier beginnt der Datenaustausch.
    }

Abbildung 25.2 verdeutlicht alle Socket-Funktionen für eine TCP-Verbindung zwischen dem Server und dem Client anhand einer Grafik.

Abbildung 25.2 Kompletter Vorgang einer TCP-Client/Server-Verbindung

Für eine UDP-Verbindung zwischen Server und Client sieht der Vorgang hingegen so aus wie in Abbildung 25.3.

Abbildung 25.3 Kompletter Vorgang einer UDP-Client/Server-Verbindung



Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
  
  Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: C von A bis Z

 C von A bis Z
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchtipps
Zum Rheinwerk-Shop: C/C++






 C/C++


Zum Rheinwerk-Shop: Einstieg in C






 Einstieg in C


Zum Rheinwerk-Shop: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Rheinwerk-Shop: C++ Handbuch






 C++ Handbuch


Zum Rheinwerk-Shop: IT-Handbuch für Fachinformatiker






 IT-Handbuch für
 Fachinformatiker


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2009
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern