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.6 (Cross-Plattform-)TCP-Echo-Server Zur nächsten ÜberschriftZur vorigen Überschrift

In diesem Abschnitt schreiben wir als Beispiel einen einfachen portablen TCP-Echo-Server mit fast allen Funktionen, die eben beschrieben wurden. Befindet sich beispielsweise die Server-Software auf einem Rechner mit der IP-Adresse 196.12.32.6, so können Sie mit der Clientanwendung unter Angabe der entsprechenden IP-Adresse einen einfachen String via Kommandozeile senden. Der Server gibt diesen String mitsamt der Herkunft des Clients (IP-Adresse) und des Datums mit Uhrzeit auf die Standardausgabe aus.


Rheinwerk Computing - Zum Seitenanfang

25.6.1 Der Client Zur nächsten ÜberschriftZur vorigen Überschrift

Hier sehen Sie den Quellcode der Clientanwendung:

/* client.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#ifdef _WIN32
/* Headerfiles für Windows */
#include <winsock.h>
#include <io.h>

#else
/* Headerfiles für UNIX/Linux */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif

#define PORT 1234
#define RCVBUFSIZE 8192

/* Funktion gibt aufgetretenen Fehler aus und
 * beendet die Anwendung. */
static void error_exit(char *errorMessage) {

#ifdef _WIN32
    fprintf(stderr,"%s: %d\n", errorMessage, WSAGetLastError());
#else
    fprintf(stderr, "%s: %s\n", errorMessage, strerror(errno));
#endif
    exit(EXIT_FAILURE);
}

int main( int argc, char *argv[]) {
    struct sockaddr_in server;
    struct hostent *host_info;
    unsigned long addr;

#ifdef _WIN32
    SOCKET sock;
#else
    int sock;
#endif

    char *echo_string;
    int echo_len;

#ifdef _WIN32
    /* Initialisiere TCP für Windows ("winsock"). */
    WORD wVersionRequested;
    WSADATA wsaData;
    wVersionRequested = MAKEWORD (1, 1);
    if (WSAStartup (wVersionRequested, &wsaData) != 0)
        error_exit( "Fehler beim Initialisieren von Winsock");
    else
        printf("Winsock initialisiert\n");
#endif

 /* Sind die erforderlichen Kommandozeilenargumente vorhanden? */
    if (argc < 3)
        error_exit("usage: client server-ip echo_word\n");

    /* Erzeuge das Socket. */
    sock = socket( AF_INET, SOCK_STREAM, 0 );


    if (sock < 0)
        error_exit( "Fehler beim Anlegen eines Sockets");

    /* Erzeuge die Socketadresse des Servers.
     * Sie besteht aus Typ, IP-Adresse und Portnummer. */
    memset( &server, 0, sizeof (server));
    if ((addr = inet_addr( argv[1])) != INADDR_NONE) {
        /* argv[1] ist eine numerische IP-Adresse. */
        memcpy( (char *)&server.sin_addr, &addr, sizeof(addr));
    }
    else {
        /* Für den Fall der Fälle: Wandle den
         * Servernamen bspw. "localhost" in eine IP-Adresse um. */
        host_info = gethostbyname(argv[1]);
        if (NULL == host_info)
            error_exit("Unbekannter Server");
        /* Server-IP-Adresse */
        memcpy( (char *)&server.sin_addr,
                host_info->h_addr, host_info->h_length );
    }
    /* IPv4-Verbindung */
    server.sin_family = AF_INET;
    /* Portnummer */
    server.sin_port = htons( PORT );

    /* Baue die Verbindung zum Server auf. */
    if(connect(sock,(struct sockaddr*)&server,sizeof(server)) <0)
        error_exit("Kann keine Verbindung zum "
                   "Server herstellen");

    /* Zweites Argument wird als "echo" beim Server verwendet. */
    echo_string = argv[2];
    /* Länge der Eingabe */
    echo_len = strlen(echo_string);

    /* den String inkl. Nullterminator an den Server senden */
    if (send(sock, echo_string, echo_len, 0) != echo_len)
        error_exit("send() hat eine andere Anzahl"
                   " von Bytes versendet als erwartet !!!!");


    /* Schließe Verbindung und Socket. */
#ifdef _WIN32
    closesocket(sock);
    /* Cleanup Winsock */
    WSACleanup();
#else
   close(sock);
#endif

    return EXIT_SUCCESS;
}

Rheinwerk Computing - Zum Seitenanfang

25.6.2 Der Server topZur vorigen Überschrift

Hier ist der Quellcode zur Server-Anwendung:

/* server.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>

#ifdef _WIN32
/* Headerfiles für Windows */
#include <winsock.h>
#include <io.h>

#else
/* Headerfiles für UNIX/Linux */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif

/* Portnummer */
#define PORT 1234

/* Puffer für eingehende Nachrichten */
#define RCVBUFSIZE 1024

#ifdef _WIN32
   static void echo(SOCKET);
#else
   static void echo( int );
#endif

static void error_exit(char *errorMessage);

/* Die Funktion gibt Daten vom Client auf stdout aus,
 * die dieser mit der Kommandozeile übergibt. */
#ifdef _WIN32
static void echo(SOCKET client_socket)
#else
static void echo(int client_socket)
#endif
{
    char echo_buffer[RCVBUFSIZE];
    int recv_size;
    time_t zeit;

    if((recv_size =
            recv(client_socket, echo_buffer, RCVBUFSIZE,0)) < 0)
        error_exit("Fehler bei recv()");
    echo_buffer[recv_size] = '\0';
    time(&zeit);
    printf("Nachrichten vom Client : %s \t%s",
            echo_buffer, ctime(&zeit));
}

/* Die Funktion gibt den aufgetretenen Fehler aus und
 * beendet die Anwendung. */
static void error_exit(char *error_message) {

#ifdef _WIN32
    fprintf(stderr,"%s: %d\n", error_message, WSAGetLastError());
#else
    fprintf(stderr, "%s: %s\n", error_message, strerror(errno));
#endif

    exit(EXIT_FAILURE);
}

int main( int argc, char *argv[]) {
    struct sockaddr_in server, client;

#ifdef _WIN32
    SOCKET sock, fd;
#else
    int sock, fd;
#endif

    unsigned int len;

#ifdef _WIN32
    /* Initialisiere TCP für Windows ("winsock"). */
    WORD wVersionRequested;
    WSADATA wsaData;
    wVersionRequested = MAKEWORD (1, 1);
    if (WSAStartup (wVersionRequested, &wsaData) != 0)
        error_exit( "Fehler beim Initialisieren von Winsock");
    else
        printf("Winsock initialisiert\n");
#endif

    /* Erzeuge das Socket. */
    sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock < 0)
        error_exit("Fehler beim Anlegen eines Sockets");

    /* Erzeuge die Socketadresse des Servers. */
    memset( &server, 0, sizeof (server));
    /* IPv4-Verbindung */
    server.sin_family = AF_INET;
    /* INADDR_ANY: jede IP-Adresse annehmen */
    server.sin_addr.s_addr = htonl(INADDR_ANY);
    /* Portnummer */
    server.sin_port = htons(PORT);

    /* Erzeuge die Bindung an die Serveradresse
     * (genauer: an einen bestimmten Port). */
    if(bind(sock,(struct sockaddr*)&server, sizeof( server)) < 0)
        error_exit("Kann das Socket nicht \"binden\"");

    /* Teile dem Socket mit, dass Verbindungswünsche
     * von Clients entgegengenommen werden. */
    if(listen(sock, 5) == -1 )
         error_exit("Fehler bei listen");

    printf("Server bereit - wartet auf Anfragen ...\n");
    /* Bearbeite die Verbindungswünsche von Clients
     * in einer Endlosschleife.
     * Der Aufruf von accept() blockiert so lange,
     * bis ein Client Verbindung aufnimmt. */
    for (;;) {
        len = sizeof(client);
        fd = accept(sock, (struct sockaddr*)&client, &len);
        if (fd < 0)
            error_exit("Fehler bei accept");
        printf("Bearbeite den Client mit der Adresse: %s\n",
           inet_ntoa(client.sin_addr));
        /* Daten vom Client auf dem Bildschirm ausgeben */
        echo( fd );

        /* Schließe die Verbindung. */
#ifdef _WIN32
        closesocket(fd);
#else
        close(fd);
#endif
    }
    return EXIT_SUCCESS;
}

Generell werden die meisten Leser dieses Beispiel am lokalen Rechner testen. Das heißt, sowohl die Server- als auch die Clientanwendung befindet sich dabei auf einem Rechner. Wie schon erwähnt wurde, ist dies dank des Loopback-Interfaces kein Problem. Die lokale IP-Adresse, die Sie auf Ihrem Rechner verwenden können, lautet hierbei 127.0.0.1 bzw. »localhost«. Wenn Sie allerdings die Möglichkeit haben, die Serveranwendung auf einem anderen System zu kompilieren und zu testen, so sollten Sie sich nicht scheuen, dies zu tun.

Abbildung 25.4 zeigt das Programm bei der Ausführung.

Abbildung 25.4 Ein Client schickt einen String an den Server.

Abbildung 25.5 Der Server bearbeitet die Anfragen des bzw. der Clients.

Natürlich stellt dieses Beispiel die primitivste Form der Netzwerkprogrammierung dar. Dennoch werden eigentlich alle wichtigen Funktionen der Netzwerkprogrammierung dazu verwendet.



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