socket: server-client



  • hallo,

    also: ich bin viel in foren unterwegs und es gibt durchaus foren, wo auch ich hilfe geb. aber bevor ich "..." poste, poste ich doch lieber, was mich am posting stört bzw. gar nichts.
    bezügl. TRUE/FALSE: hmm dachte schon, dass das ok ist. aber danke für den einwand. hatte vorher SUCCESS/ERROR damit definiert...

    bezügl. accept(): ich hatte accept auch schon VOR der schleife. dann funktionierte das aber leider auch nicht richtig. der server nahm nur einmalig messages entgegen -> dann war schluss...

    hat sonst noch jemand einen tipp?

    thx



  • ich bin auch in vielen foren unterwegs, und da hat der hilfe suchende immer kleine broetchen gebacken

    wie du siehst hat er den post 3 mal editiert, evtl hat er sich verlesen, sich vertan, im falschen thread, was weiss ich? also bitte erstmal nachdenken

    was dein problem angeht: es ist sehr offensichtlich was da alles nicht funktionieren kann, und das so wenig antworten liegt evtl auch dadrann das der code sehr chaotisch und unuebersichtlich ist, und vor fehlern nur so strotzt

    ich habe mal versucht, eine version zu machen, die funktioniert, aber den code nur minimal veraendert, damit du auch was davon hast, denn normalerweisse muesst man das ganze programm umschreiben....

    server.c

    #include <stdio.h>
    #include <stdlib.h>
    
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <unistd.h>
    #include <signal.h>
    #include <unistd.h>
    
    #include "general.h"
    
    int cli_sd;
    void user_abort(int signal);
    
    int read_line(int newSd, char *line_to_return);
    
    void user_abort(int signal) {
        if ( signal == SIGINT ) {
            printf("\ncaughed abort signal\n");
            printf("terminating...\n");
            close(cli_sd);
            exit(TRUE);
        }
    }
    
    int main(int argc, char **argv) {
    
        signal(SIGINT, user_abort);
    
        int sd, received_bytes;
        char message_buffer[MAXBUFFER];
        struct sockaddr_in server_addr;
    
        sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if ( sd == -1 ) {
            printf("cannot open socket\n");
            return FALSE;
          }
    
        server_addr.sin_family      = AF_INET;
        server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
        server_addr.sin_port        = htons(SERVER_PORT);
    
        if ( bind(sd, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1 ) {
            printf("cannot bind port\n");
            return FALSE;
        }
    
        if ( listen(sd, 3) == FALSE ) {
            printf("cannot start listening...\n");
            return FALSE;
        }
    
            if ( (cli_sd = accept(sd, NULL, NULL)) == -1 ) {
                printf("cannot accept client...\n");
                return FALSE;
            }
    
        while (1) {
            bzero(&message_buffer, sizeof(message_buffer));
    
            if ((received_bytes = recv(cli_sd, message_buffer, MAXBUFFER, 0)) <= 0) {
                    close(cli_sd);
                    return 0;
            }
            else {
                printf("received [%s]\n\n", message_buffer);
            }
    
        }
        return 0;
    
    }
    

    client.c

    #include <stdio.h>
    #include <stdlib.h>
    
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <unistd.h>
    #include <signal.h>
    #include <string.h>
    
    #include "general.h"
    
    #define ELEMENTS 9
    
    int main(int argc, char **argv) {
        int sd, sent_bytes, i;
        char *messages[] = {
            "hello server?",
            "are you there",
            "hope so",
            "lalllaaa",
            "fifth",
            "sixth",
            "seventh",
            "eight",
            "nineth",
            "tenth"
        };
        struct sockaddr_in local_addr;
        struct sockaddr_in server_addr;
        struct hostent *host;
    
        host = gethostbyname(SERVER_IP);
        if ( host == NULL ) {
            printf("unknown host [%s]\n", SERVER_IP);
            return FALSE;
        }
    
        server_addr.sin_family = host->h_addrtype;
        memcpy((char *) &server_addr.sin_addr.s_addr, host->h_addr_list[0], 
    host->h_length);
        server_addr.sin_port = htons(SERVER_PORT);
    
        sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if ( sd < 0 ) {
            printf("cannot open socket\n");
            return FALSE;
        }
    
        local_addr.sin_family      = AF_INET;
        local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
        local_addr.sin_port        = htons(0);
    
        if ( (connect(sd, (struct sockaddr *) &server_addr, 
    sizeof(server_addr))) < 0 ) {
            printf("cannot connect\n");
            return FALSE;
        }
    
        for ( i=0; i<ELEMENTS; i++ ) {
            sent_bytes = send(sd, *(messages+i), MAXBUFFER, 0);
            if ( sent_bytes < 0 ) {
                printf("could not send data\n");
                close(sd);
                return FALSE;
    
            }
            printf("%s: data %u sent [%s]\n", SERVER_IP, SERVER_PORT, messages[i]);
        }
        close(sd);
        return TRUE;
    }
    


  • daq schrieb:

    ich bin auch in vielen foren unterwegs, und da hat der hilfe suchende immer kleine broetchen gebacken

    das heißt?

    wie du siehst hat er den post 3 mal editiert, evtl hat er sich verlesen, sich vertan, im falschen thread, was weiss ich? also bitte erstmal nachdenken

    sorry, hab ich nicht gesehen!

    was dein problem angeht: es ist sehr offensichtlich was da alles nicht funktionieren kann, und das so wenig antworten liegt evtl auch dadrann das der code sehr chaotisch und unuebersichtlich ist, und vor fehlern nur so strotzt

    sorry, das kann ich nicht so stehen lassen...
    was heißt chaotisch und unübersichtlich?
    sei doch so nett und erklär mir, WAS chaotisch/unübersichtlich ist.



  • geht es denn jetzt?

    zu dem code style:

    du includierst alles moegliche, egal ob dus brauchst oder nicht, defs von prototypes sind sehr unschoen platziert, deine schleife(n) sind komisch aufgebaut, du defenierst und initialisiert sachen die du anscheinend net brauchst (oder hab ich was uebersehen oder wieso machst du server_addr und local_addr)...



  • daq schrieb:

    geht es denn jetzt?

    ja, deine version geht - danke!
    find aber den fehler in meiner nicht...

    du includierst alles moegliche, egal ob dus brauchst oder nicht

    naja, socket braucht einiges... ausserdem hab ich länger herumprobiert. aber das ist sicher kein grund den code chaotisch und unübersichtlich zu nennen oder?

    defs von prototypes sind sehr unschoen platziert

    dh: weil nicht in einer header datei? -> kommt noch

    deine schleife(n) sind komisch aufgebaut

    das heißt???

    du defenierst und initialisiert sachen die du anscheinend net brauchst

    jo, hätt vor dem post ein code clean up machen müssen...

    thx für deinen beitrag!!

    cheers



  • hab mal eben eine version geschrieben die dasselbe macht aber in einem etwas sauberen code style, jetzt nur als anregung

    1. einfachere schleifen, bedingungen werden direkt reingebaut
    2. weniger files included (na soviel brauchen sockets jetz auch net ;))
    3. fehlermeldungen werden mit perror zurueckgegeben

    und den rest siehste ja, signal und dns aufloesung is jetz nich drinn, sollte jetz nur mal so als anregung sein, kannst ja nochmal mit deiner version vergleichen, evtl siehste was ich mit "chaotisch und unuebersichtlich" meinte 😉

    server.c

    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    
    #include "header.h"
    
    int main()
    {
    
            // Definitions
            int sockfd, ret;
            struct sockaddr_in conn_addr;
            char buffer[MSG_LEN];
    
            // Build Socket
            sockfd = socket(AF_INET, SOCK_STREAM, 0);
    
            conn_addr.sin_family      = AF_INET;
            conn_addr.sin_addr.s_addr = htonl(INADDR_ANY);
            conn_addr.sin_port        = SERVER_PORT; 
    
            if ( bind(sockfd, SA &conn_addr, sizeof(conn_addr)) == -1 ) {
                    printf("cannot bind port\n");
                    return 1;
            } 
    
            if ( listen(sockfd, 3) == -1 ) {
                    perror("listen error");
                    return 1;
            } 
    
            // wait for client
            if ( (sockfd = accept(sockfd, NULL, NULL)) == -1 ) {
                perror("accept error");
                return 1;
            } 
    
            // loop to receive data from client and print it out
            while( (ret = recv(sockfd, buffer, MSG_LEN, 0)) > 0) {
                    printf("%s\n", buffer);
                    bzero(&buffer, sizeof(buffer));
            }
    
            if(ret == -1) {
                    perror("recv error");
                    return 1;
            }
    
            return 0;
    }
    

    client.c

    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    
    #include "header.h"
    
    // array of pointers in which messages are stored
    char *messages[] = {
            "hello server?",
            "are you there",
            "hope so",
            "lalllaaa",
            "fifth",
            "sixth",
            "seventh",
            "eight",
            "nineth",
            "tenth"
    }; 
    
    int main() 
    {
            int sockfd, ret, c;
            char buffer[MSG_LEN];
            struct sockaddr_in conn_addr;
    
            conn_addr.sin_family = AF_INET;
            conn_addr.sin_port = SERVER_PORT;
            inet_pton(AF_INET, SERV_IP , &conn_addr.sin_addr);
    
            sockfd = socket(AF_INET, SOCK_STREAM, 0);
    
            if( (ret = connect(sockfd, SA &conn_addr, sizeof(conn_addr))) < 0) {
                    perror("connect error");
                    return 1;
            }
    
            for(c = 0; c <= NUMBER_OF_MESSAGES; c++) {
                if( (ret = send(sockfd, messages[c], MSG_LEN, 0)) < 0)
                            perror("send error");
                printf("SEND\t%s\n", messages[c]);
            }
    
            close(sockfd);
    
            return 0;
    }
    

    dein hauptfehler, weshalb das garnet erst gehen konnte, lag in deine server schleife

    while ( 1 ) {
    if ( (cli_sd = accept(sd, NULL, NULL)) == -1 ) {
    printf("cannot accept client...\n");
    return FALSE;
    }
    received_bytes = recv(cli_sd, message_buffer, MAXBUFFER, 0);
    if ( received_bytes == FALSE ) {
    printf("error when reading the socket of [%d]\n", cli_sd);
    exit(FALSE);
    } else if ( received_bytes == 0 ) {
    ; /* pending */
    } else {
    printf("received [%s]\n", message_buffer);
    }
    close(cli_sd);
    }

    du nimmst in der schleife die erste connection an, empfaengst den string, gibts ihn aus, SCHLIESST die connection wieder und wartest bei accept. ist ja klar das nur der erste string empfangen wird 😉



  • ups die header fehlte, die is ganz unspektakulaer

    header.h

    #define MSG_LEN 128
    
    #define SERVER_PORT 1337
    
    #define SA (struct sockaddr *)
    
    #define SERV_IP "127.0.0.1"
    
    #define NUMBER_OF_MESSAGES 9
    


  • hey daq!

    cool, danke dir!
    das mit dem SA makro is auch a coole idee 🙂
    stimmt, dein code ist wesentlich übersichtlicher!

    ciao



  • btw. bzero is in der strings.h definiert 🙂
    weiters braucht man für close die unistd.h und für inet_pton die arp/inet.h

    weiters sind "//" keine gültigen kommentare lt. ansi

    :xmas2:

    bei den for/ifs mach ich zB folgendes:
    if_(_bedingung_)
    {
    oder
    for_(_i=0;_bedingung;_i++_)
    {

    dh: leerzeichen sind drinnen. um es lesbarer zu machen und um zu verdeutlichen, dass for/if keine funktionen sind... was hältst du davon?
    danke nochmal!!



  • wieso wird dadurch deutlich das es keine funktionen sind? whitespaces sind C egal, ein funktion call kann genauso aussehen, sagen wir du hast ne funktion geschrieben die bla heisst

    bla ( bla, blubb, bli ) ;

    geht genauso.

    also ich finde das nicht so schoen, das erinnert irgenwie ans plenken

    aber letzendlich muss eh jeder seinen coding style finden 😉



  • ja, das mit funktion_(_sadfd_) is mir klar. aber ich schreib halt bei funktionen KEINE leerzeichen und bei if/while/for schon...

    ciao



  • @daq + hephaistos
    Eine kleine Sache ist noch anzumerken. Überlegt euch mal noch Fehlercodes. Immer nur 1 zurückzugeben ist nicht sehr informativ. Der Benutzer kann mit den Fehlermeldungen natürlich was anfangen, aber was ist, wenn der Aufrufer kein Mensch ist sondern ein anderes Programm? Woran erkennt es nun, was genau schief gelaufen ist?



  • @AJ: hast natürlich recht. für diesen kleinen socket test war das aber nicht von nöten.

    danke trotzdem für den einwand!

    cheers


Anmelden zum Antworten