Alternierendes Bitprotokoll mit Signalen - Fehlersuche



  • Hallo,

    ich habe zur seit die Aufgabe ein Alternierendes Bitprotokoll mit Signalen in C zu implementieren.
    Kurze Erklärung:
    Initiator und Responder haben jeweils einen String den sie verschicken. z.B. "Hallo" "Tschüß". Es werden dann immer zu einem Zeichen abwechselnd der Bit 0 oder 1 angehängt.
    Der Initiator sendet zuerst H0 und der Responder meldet H0 empfangen. Dann sendet Responder T0 und Initiator empfängt T0. Dann sendet Initiator a1 usw.

    Als zweiten Teil sollte man den Fall simulieren, dass der Initiator Kanal fehleranfällig ist. Heißt kommt eine Antwort nicht beim Responder an, so wird sie nochmal geschickt, solange bis der Responder richtig reagiert.

    Ich verstehe meine Ausgabe nicht ganz. In gewisser weise funktioniert alles, aber manche Dinge eben doch nicht, wie sie sollen. Leider kann ich mir das auch nicht erklären.

    Zu den Fehlern:
    -Der erste Teil mit dem Hin- und Herschicken funktioniert zu 90%. An sich macht es das was es soll, aber manchmal empfängt der Responder andere Nachrichten als der Initiator gesendet hat.
    -Wenn ein Fehler auftrifft wird bei mir meistens, der falsche Bit mitgeschickt. Z.B. Error H0 Sender sends H1. Manchmal kommt es aber auch vor, dass dies korrekt geschieht.

    Es dürfen nur die Funktionen und Bibliotheken, die bereits im Code stehen verwendet werden. Die Grundstrucktur sollte bleiben.

    #include <sys/types.h>
    #include <signal.h>
    #include <stdlib.h>
    #include <time.h>
    #include <stdio.h>
    #include <sys/wait.h>
    #include <unistd.h>
    #include <string.h>
    
    /*
        TODO:
        Fehler allg beim Senden finden.
        Sender sends J0 - Receiver receive H1
        Fehler finden bei Error senden.
        Ziel: Konstant den richtigen String senden -> Error J0 - Sending J0, nicht J1
    */
    
    int MSG_LEN = 3;
    char text[]  = {'1','2','\0'};
    
    int pipe_sender[2];
    int pipe_receiver[2];
    
    //rate to fail
    float failrate = 0.1;
    
    int i = 0;
    
    char message[50] = "";
    
    char bit = '0';
    
    
    
    //sender callback
    void sender(){
        read(pipe_receiver[0], &text, MSG_LEN);
        printf("Sender receives \t %s \n", text);
    }
    
    //receiver callback
    void receiver(){
        read(pipe_sender[0], &text, MSG_LEN);
        printf("Receiver receives \t %s \n", text);
    }
    
    //help routine for sending data and bit
    void send(int fd, char data, char bit){
        char buff[MSG_LEN];
        buff[0] = data;
        buff[1] = bit;
        buff[2] = '\0';
        write(fd, &buff, MSG_LEN);
    }
    
    //alarm callback
    void sender_alarm(){
        //printf("Test ");
        if(bit == '0'){
            send(pipe_sender[1], message[i], '0');
        }else{
            send(pipe_sender[1], message[i], '1');
        }
    }
    
    
    int main(){
        int pid;
        struct sigaction action = {0};
    
        srand(time(NULL));
    
        //open pipes
        pipe(pipe_sender);
        pipe(pipe_receiver);
    
        pid = fork();
    
    
        //parent
        if(pid > 0){
            //close unused pipes
            close(pipe_sender[0]);
            close(pipe_receiver[1]);
    
            //register callback function via SIGUSR1 signal
            action.sa_handler = sender;
            sigaction(SIGUSR1, &action, 0);
    
            //register callback function via SIGALRM signal
            action.sa_handler = sender_alarm;
            sigaction(SIGALRM, &action, 0);
    
            sleep(1);
    
            strcpy(message, "TheQuickBrownFoxOle");
            char bit = '0';
            i = 0;
    
            send(pipe_sender[1], message[i], bit);
            printf("Sender sends \t\t %c%c \n", message[0], bit);
            kill(pid, SIGUSR2);
            i++;
    
            int state = 0;
    
    
            //state automat
            while(i < strlen(message)){
                switch(state){
                    case 0:
                        pause();
                        sleep(1);
                        if(text[1] == '0'){
                            alarm(0);
                            state = 2;
                        }else{
                            alarm(0);
                            state = 1;
                        }
                        i++;
                        break;
                    case 1:
                        if((float) rand() /(float) RAND_MAX >= failrate){
                            bit = '0';
                            send(pipe_sender[1], message[i], bit);
                            printf("Sender sends \t\t %c%c \n", message[i], bit);
                            kill(pid, SIGUSR2);
                            state = 0;
                        }else{
                            printf("Error %c%c \n", message[i], bit);
                            alarm(3);
                            sleep(1);
                        }
                        break;
                    case 2:
                        if((float) rand() /(float) RAND_MAX >= failrate){
                            bit = '1';
                            send(pipe_sender[1], message[i], bit);
                            printf("Sender sends \t\t %c%c \n", message[i], bit);
                            kill(pid, SIGUSR2);
                            state = 0;
                        }else{
                            printf("Error %c%c \n", message[i], bit);
                            alarm(3);
                            sleep(1);
                        }
                        break;
                    default:
                        break;
                }
            }
    
            sleep(2);
            close(pipe_sender[1]);
            close(pipe_receiver[0]);
            exit(0);
        //child
        }else{
            close(pipe_sender[1]);
            close(pipe_receiver[0]);
    
            action.sa_handler = receiver;
            sigaction(SIGUSR2, &action, 0);
    
            strcpy(message, "JumpsOverTheLazyDog");
    
            int j = 0;
            int state = 1;
            char bit = '0';
    
            while(j < strlen(message)){
                switch(state){
                    case 0:
                       pause();
                       sleep(1);
                       if(text[1] == '1'){
                            state = 2;
                       }else{
                            state = 1;
                       }
                       j++;
                        break;
                    case 1:
                        bit = '0';
                        send(pipe_receiver[1], message[j], bit);
                        printf("Receiver sends \t\t %c%c \n", message[j], bit);
                        kill(getppid(), SIGUSR1);
                        state = 0;
                        break;
                    case 2:
                        bit = '1';
                        send(pipe_receiver[1], message[j], bit);
                        printf("Receiver sends \t\t %c%c \n", message[j], bit);
                        kill(getppid(), SIGUSR1);
                        state = 0;
                        break;
                    default:
                        break;
                }
    
            }
            sleep(2);
            close(pipe_sender[0]);
            close(pipe_receiver[1]);
            //exit(0);
        }
        printf("Fertig!");
        return 0;
    }
    
    

    MfG,
    werdas34


  • Mod

    Ahh! Globaler State überall! Globale Variablen sind die Wurzel allen Böses! Wie soll hier jemand nachvollziehen können, welchen Wert deine Variablen an welcher Stelle haben, wenn sie sie ständig überall ändern können? Das kannst ja nicht einmal du selber, und du hast das geschrieben!

    Daher nur Spekulationen:

    1. Der Fehler verschwindet wahrscheinlich von ganz alleine, wenn du das Programm noch einmal neu schreibst ohne globale Variablen. Denn dann besteht eine hohe Chance, dass das Programm auch tut, was du denkst.
    2. 2xPipe? Häh? Was soll das denn modellieren? Normalerweise macht man eine Pipe, forkt dann, und dann haben die beiden Prozesse jeweils ein Ende von der Pipe. Würde mich bei all dem sonstigen Chaos hier nicht wundern, wenn du damit durcheinander kommst, wer hier wann was über welchen Kanal wohin schickt.
    3. Du gibst manchmal Strings mit '%s' aus, von denen du nicht sicher wissen kannst, ob sie nullterminiert sind. Mit Folgen, falls du dich irrst.

    Aber vor allem Punkt 1. Mach das anders. Wirklich. Und schreib nie wieder ein Programm, das auch nur so ähnlich aussieht, als hätte es globale Variablen.



  • Danke für deine Nachricht.
    Zu 2. Das ist vom Professor vorgegeben mit den 2xPipe.
    Die Globalen Variablen sind noch aus Experimenten dar.

    Diese drei globalen Variablen:
    int i = 0;
    char message[50] = "";
    char bit = '0';
    könnte man als Parameter der alarm_sender Funktion implementieren. Nur wie übergebe ich sie dann? Schließlich wird alarm_sender an SIGALRM gekoppelt.

    Das würde mir schon vieles erleichtern und ich könnte einige globale Variablen entfernen und manche auf const setzten.

    Gruß,
    werdas34


  • Mod

    Ja, die Übergabe von Variablen an Callbacks, die keine Variablenübergabe unterstützen (primitv, aber gibt's leider...) ist die eine Sache, wo man am häufigsten globale Variablen braucht und auch rechtfertigen kann. Aber braucht man das denn hier? Bring dein Protokoll doch erst einmal so, ohne Signalhandler zum Laufen. Also ein fester Programmablauf, wer wann wo was sendet. Da hast du viel besser kontrollierbare Laborbedingungen. Meinetwegen mit primitiven sleeps zur Synchronisierung, falls nötig.

    Bezüglich der Pipes wäre es vielleicht auch ein Plan, deinen Prof zu ignorieren. Wozu muss ein Prozess wissen, ob er Sender oder Empfänger ist? Er ist doch immer beides und hat entsprechend den Ein- und den Ausgang seiner einen Pipe. Da ist dann immer klar, wohin man ausgehende Nachrichten schicken muss und wo man eingehendes empfangen muss, ohne dass man erst seine eigene Identität feststellen braucht.


  • Gesperrt

    @SeppJ sagte in Alternierendes Bitprotokoll mit Signalen - Fehlersuche:

    Wozu muss ein Prozess wissen, ob er Sender oder Empfänger ist?

    Vielleicht weil er senden oder empfangen soll?


  • Mod

    @RBS2 sagte in Alternierendes Bitprotokoll mit Signalen - Fehlersuche:

    @SeppJ sagte in Alternierendes Bitprotokoll mit Signalen - Fehlersuche:

    Wozu muss ein Prozess wissen, ob er Sender oder Empfänger ist?

    Vielleicht weil er senden oder empfangen soll?

    Komischerweise hat ja ein Funkgerät auch nur einen Knopf, mit dem man zwischen den zwei Modi Senden und Empfangen umschalten kann, anstatt 4 Modi für Senden als Sender, Empfangen als Sender, Empfangen als Empfänger, und Senden als Empfänger. Komisch, wie die das schaffen.



  • Was es mit den zwei Pipes auf sich hat kann ich nicht erklären, aber ich muss, um für die Prüfung zugelassen zu werden, das Programm nach Aufgabenstellung lösen. Die Aufgabenstellung sieht es mit zwei Pipes und Signalen vor.

    Ich habe heute nachmittag nochmal den Code bearbeitet und die Datenübertragung funktioniert soweit. Was nicht funktioniert ist der Fehlerkanal.
    Die Daten werden korrekt geschickt, dann kommt der Error z.B Error e1 - d.h. Nachricht e1 wurde nicht erfolgreich geschickt. Da sollte der Sender erneut e1 senden. Jedoch wird dann immer e0 gesendet, bis beim erstmaligen Auftreten des Errors - dort funktioniert alles wie geplant.

    Ich habe jedoch weitgehenst auf den handler für den alarm_sender verzichtet. Wahrscheinlich brauche ich ihn, um das vollständig und korrekt zu lösen, jedoch habe ich absolut keine Ahnung wie ich das machen könnte.

    Der aktuelle Code:

    #include <sys/types.h>
    #include <signal.h>
    #include <stdlib.h>
    #include <time.h>
    #include <stdio.h>
    #include <sys/wait.h>
    #include <unistd.h>
    #include <string.h>
    
    /*
        TODO:
        Fehler allg beim Senden finden. - Vermutlich gelöst
        Sender sends J0 - Receiver receive H1
        Fehler finden bei Error senden.
        Ziel: Konstant den richtigen String senden -> Error J0 - Sending J0, nicht J1
    */
    
    const int MSG_LEN = 3;
    char text[]  = {'1','2','\0'};
    
    int pipe_sender[2];
    int pipe_receiver[2];
    
    //rate to fail
    const float failrate = 0.5;
    
    /* int i = 0;
    
    char message[50] = "";
    
    char bit = '0';
    */
    
    
    //sender callback
    void sender(){
        read(pipe_receiver[0], &text, MSG_LEN);
        printf("Sender receives \t %c%c \n", text[0], text[1]);
    }
    
    //receiver callback
    void receiver(){
        read(pipe_sender[0], &text, MSG_LEN);
        printf("Receiver receives \t %c%c \n", text[0], text[1]);
    }
    
    //help routine for sending data and bit
    void send(int fd, char data, char bit){
        char buff[MSG_LEN];
        buff[0] = data;
        buff[1] = bit;
        buff[2] = '\0';
        write(fd, &buff, MSG_LEN);
    }
    
    //alarm callback
    void sender_alarm(){
        //printf("Test \n");
        /*
        if(bit == '0'){
            send(pipe_sender[1], message[i], '0');
        }else{
            send(pipe_sender[1], message[i], '1');
        }
        */
    }
    
    
    int main(){
        int pid;
        char message[50] = "";
        struct sigaction action = {0};
    
        srand(time(NULL));
    
        //open pipes
        pipe(pipe_sender);
        pipe(pipe_receiver);
    
        pid = fork();
      //  printf("%d", pid);
    
    
        //parent
        if(pid > 0){
            //close unused pipes
            close(pipe_sender[0]);
            close(pipe_receiver[1]);
    
            //register callback function via SIGUSR1 signal
            action.sa_handler = sender;
            sigaction(SIGUSR1, &action, 0);
    
            //register callback function via SIGALRM signal
            action.sa_handler = sender_alarm;
            sigaction(SIGALRM, &action, 0);
    
            sleep(1);
    
            int errorHelp = 0;
            strcpy(message, "TheQuickBrownFoxOle");
            char bit = '0';
            int i = 0;
    /*
            send(pipe_sender[1], message[i], bit);
            printf("Sender sends \t\t %c%c \n", message[0], bit);
            kill(pid, SIGUSR2);
            i++;
    */
            int state = 1;
    
    
            //state automat
            while(i < strlen(message)){
                switch(state){
                    case 0:
                        pause();
                        sleep(1);
                        if(text[1] != '0'){
                         //   alarm(0);
                            state = 2;
                        }else{
                         //   alarm(0);
                            state = 1;
                        }
                        i++;
                        break;
                    case 1:
                        if((float) rand() /(float) RAND_MAX >= failrate){
                            bit = '0';
                            send(pipe_sender[1], message[i], bit);
                            printf("Sender sends \t\t %c%c \n", message[i], bit);
                            kill(pid, SIGUSR2);
                            state = 0;
                        }else{
                            printf("Error %c%c \n", message[i], bit);
                            alarm(3);
                            sleep(1);
                        }
                        break;
                    case 2:
                        if((float) rand() /(float) RAND_MAX >= failrate){
                            bit = '1';
                            send(pipe_sender[1], message[i], bit);
                            printf("Sender sends \t\t %c%c \n", message[i], bit);
                            kill(pid, SIGUSR2);
                            state = 0;
                        }else{
                            printf("Error %c%c \n", message[i], bit);
                            alarm(3);
                            sleep(1);
                        }
                        break;
                    default:
                        break;
                }
            }
    
            sleep(2);
            close(pipe_sender[1]);
            close(pipe_receiver[0]);
            exit(0);
        //child
        }else if(pid == 0){
            close(pipe_sender[1]);
            close(pipe_receiver[0]);
    
            action.sa_handler = receiver;
            sigaction(SIGUSR2, &action, 0);
    
            strcpy(message, "JumpsOverTheLazyDog");
    
            int j = 0;
            int state = 1;
            char bit = '0';
    
            while(j < strlen(message)){
                switch(state){
                    case 0:
                        pause();
                        sleep(1);
                        if(text[1] == '0'){
                            alarm(0);
                            state = 2;
                        }else{
                            alarm(0);
                            state = 1;
                        }
                        j++;
                        break;
                    case 1:
                        bit = '0';
                        send(pipe_receiver[1], message[j], bit);
                        printf("Receiver sends \t\t %c%c \n", message[j], bit);
                        kill(getppid(), SIGUSR1);
                        state = 0;
                        break;
                    case 2:
                        bit = '1';
                        send(pipe_receiver[1], message[j], bit);
                        printf("Receiver sends \t\t %c%c \n", message[j], bit);
                        kill(getppid(), SIGUSR1);
                        state = 0;
                        break;
                    default:
                        break;
                }
    
            }
            sleep(2);
            close(pipe_sender[0]);
            close(pipe_receiver[1]);
            //exit(0);
        }
        printf("Fertig!");
        return 0;
    }
    
    

    Gruß,
    werdas34


  • Gesperrt

    @SeppJ sagte in Alternierendes Bitprotokoll mit Signalen - Fehlersuche:

    @RBS2 sagte in Alternierendes Bitprotokoll mit Signalen - Fehlersuche:

    @SeppJ sagte in Alternierendes Bitprotokoll mit Signalen - Fehlersuche:

    Wozu muss ein Prozess wissen, ob er Sender oder Empfänger ist?

    Vielleicht weil er senden oder empfangen soll?

    Komischerweise hat ja ein Funkgerät auch nur einen Knopf, mit dem man zwischen den zwei Modi Senden und Empfangen umschalten kann, anstatt 4 Modi für Senden als Sender, Empfangen als Sender, Empfangen als Empfänger, und Senden als Empfänger. Komisch, wie die das schaffen.

    Schlechter Vergleich. Aber jetzt kapiere ich was du willst. Der OP braucht natürlich zwei Transceiver, d.h. beide müssen senden und empfangen können, weil sie auch Steuersignale austauschen müssen.


Anmelden zum Antworten