[C/C++] Netzwerk-Programmierung Daten andauernd schicken

Dieses Thema im Forum "Programmierung & Entwicklung" wurde erstellt von Thrake7, 13. August 2009 .

Status des Themas:
Es sind keine weiteren Antworten möglich.
  1. 13. August 2009
    Netzwerk-Programmierung Daten andauernd schicken

    Hi Leute!

    Ich versuche gerade über Netzwerk an einem Server andauernd Daten zu verschicken.
    Das problem ist nur: Wie mache ich das?

    Also, ich habe mal dieses Beispielprogramm mit angeschaut:
    http://openbook.galileocomputing.de/c_von_a_bis_z/c_028_005.htm#RxxobKap02800504002D211F04918C

    mein code (Client Seite) sieht so aus:
    Code:
    /* client.c */
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    /* Headerfiles fuer UNIX/Linux */
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #define PORT 1234
    #define RCVBUFSIZE 8192
    #define IPADDR "10.0.2.55"
    #define MESSAGE "Hello Network"
    /* Funktion gibt aufgetretenen Fehler aus und
     * beendet die Anwendung */
    static void error_exit(char *errorMessage) {
     fprintf(stderr, "%s: %s\n", errorMessage, strerror(errno));
     exit(EXIT_FAILURE);
    }
    int main( int argc, char **argv) {
     struct sockaddr_in server;
     struct hostent *host_info;
     unsigned long addr;
     int sock;
    
     char *echo_string;
     int echo_len;
    
     /* 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( IPADDR)) != INADDR_NONE) {
     /* argv[1] ist eine numerische IP-Adresse */
     memcpy( (char *)&server.sin_addr, &addr, sizeof(addr));
     }
     else {
     /* Fuer den Fall der Faelle: 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 = MESSAGE;
     /* Laenge der Eingabe */
     echo_len = strlen(echo_string);
     /* Denn String inkl. Nullterminator an den Server senden */
    
     /*if (send(sock, echo_string, echo_len, 0) != echo_len)
     error_exit("send() hat eine unterschiedliche Anzahl"
     " von Bytes versendet, als erwartet !!!!");*/
     send(sock, "Hello TEST2", strlen("Hello Test2"), 0);
    
     /* Schliesse Verbindung und Socket */
    
    
     close(sock);
     return EXIT_SUCCESS;
    }
    Ist eigentlich fast das, was bei Galileo drinsteht und funktioniert auch. Ich schicke einfach nur ein "Hello TEST2" an den Server.

    Nun will ich aber andauernd "Hello Test2" schicken und habe versucht, die zeile
    Code:
     send(sock, "Hello TEST2", strlen("Hello Test2"), 0);
    in einer while schleife zu verpacken und damit nicht das netzwerk zu überlastet ist, habe ich noch ein sleep(2) eingebaut, also so:

    Code:
     while(1) {
     send(sock, "Hello TEST2", strlen("Hello Test2"), 0);
     sleep(2);
     }
    Wenn ich das mache, und ausführe, kriegt der Server nur eine Nachricht und das Programm beendet sich einfach so.
    Kann mir einer erklären, was ich falsch mache?
    Wenn ich 2mal den Befehl: send(sock, "Hello TEST2", strlen("Hello Test2"), 0); ausführe, dann kriegt der Server auch 2 mal die Nachricht. Warum funktioniert das nicht in der While schleife und warum bricht das Programm einfach ab, obwohl ich mich in einer endlosschleife befinde?

    mfg
    Thrake7
     
  2. 13. August 2009
    AW: Netzwerk-Programmierung Daten andauernd schicken

    hi!

    ohne zu wissen wie dein server programm aussieht könnte ich mir vorstellen, dass du da einfach vergessen hast auch öfter nach nachrichten zu schauen. also die clients abfragen mit denen du verbunden bist, ob eine nachricht vorliegt. dafür gibt es verschiedene möglichkeiten, aber auf jeden fall muss dass auch irgendwie in ne schleife... (also die recv() Funktion)

    hab mich selbst vor kurzem erst ein bisschen damit auseinander gesetzt und fand diese seiten eigentlich ziemlich hilfreich:

    c-worker.ch - Winsock Tutorials / C++ / Php Text DB API
    c++.de :: Sockets und das HTTP-Protokoll

    mfg
     
  3. 13. August 2009
    AW: Netzwerk-Programmierung Daten andauernd schicken

    Das ist genau das von Galileo:
    also das da:

    Code:
    /* 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);
    /* Funktion gibt Daten vom Client auf dem stdout aus,
     * welche 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));
    }
    /* Funktion gibt 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
     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 Socket");
     /* 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 solange,
     * 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 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;
    }
    Ist ja auch in dem server drin... wenn ich 2 Sendbefehle ausführe, kriegt er ja auch 2 nachrichten.
     
  4. 13. August 2009
    AW: Netzwerk-Programmierung Daten andauernd schicken

    also ich sehe in der endlosschleife nur nen accept aufruf. damit empfängst du aber nicht die nachrichten. damit kannst du nur neue verbindungen annehmen. bin mir nicht mehr ganz sicher, aber der recv()-aufruf müsste da eigentlich stehen. der blockiert ebenfalls solange bis er eine nachricht von einem entsprechenden client erhält.

    auf dieser seite ist das wirklich wunderbar erklärt:
    Winsock Tutorial: Grundlagen und TCP

    // edit: also bei einem server war es so, dass dieser einen socket hat, der neue verbindungen annimt und andere sockets hat, die mit den clients verbunden sind und mit denen komunizieren. diese verschiedenen sockets seh ich bei dir nicht. bei dir würde der eine socket ("fd") immer wieder die neuste verbindung annehmen und den letzten client verlieren (wenn ich das richtig sehe)..
    um dann später alle sockets behandeln zu können nimmt man dann meistens ein FD_SET. damit kann man umgehen, dass der thread in einer listen() - oder accept()- methode gefangen bleibt...
    (multithreading ist dann z.B. eine andere Variante, mehrere sockets zu behandeln)

    // edit: hab grad mein server programm wiedergefunden, das genau das macht was du möchtest. wenn du willst kann ich es posten.. oder du versuchst es selbst nochmal... wie gesagt, der erste link den ich geschickt hab kann ich sehr empfehlen. danach hab ichs auch gemacht. (btw. find ich den galileo-code ziiieemlich unübersichtlich^^)
     
  5. 13. August 2009
    AW: Netzwerk-Programmierung Daten andauernd schicken

    Er ruft aber auch andauernd die Funktion echo auf:
    Code:
    #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));
    
    }
    Da ist ja auch der recv() drin.

    Ich will die Verbindung von nur einem Client aufbauen. Dazu brauche ich doch eigentlich nur einen Socket, oder etwa nicht?
    Auch wenn ich den Socket am ende nicht schließe bzw. beende, krieg ich nur eine Nachricht und er verschickt nie andauernd nachricht.

    Das Problem an http://www.c-worker.ch/tuts/wstut_op.php#srvsock ist, dass er da nur auf Windows Programmierung eingeht. Ich will aber eine Verbindung von einem Windows-PC zu einem Linux-PC aufbauen. Dieser soll bestimmte daten (die ich schon abgefangen habe) an den Linux PC senden. Ich will also sozusagen eine Verbindung der beiden aufbauen und andauernd Daten senden (weil sich diese mit der Zeit immer ändern).
     
  6. 13. August 2009
    AW: Netzwerk-Programmierung Daten andauernd schicken

    ja, aber soweit kommt er garnicht. weil der accept()-aufruf davor den thread blockiert bis sich ein neuer client meldet

    //edit: pack mal das accept() vor die schleife und in die schleife dann recv() bzw. deine echo-methode. dann müsste es eigentlich laufen
     
  7. 13. August 2009
    AW: Netzwerk-Programmierung Daten andauernd schicken

    hmmm... scheint jetzt alles zu funktionieren, wie ich will
    Vielen herzlichen Dank!

    Bw ist draußen.
     
  8. Video Script

    Videos zum Themenbereich

    * gefundene Videos auf YouTube, anhand der Überschrift.