Linux трубы и буферы, не уверен, как заставить цикл работать - PullRequest
0 голосов
/ 05 октября 2018

Я пишу программу DB на C для класса Unix, который я беру.В то время как мне удалось заставить все каналы, буферы и команды работать, циклы while бросают ME для цикла.Программа полностью выполнит первую команду, примет вторую команду, но затем быстро завершит работу.Я загрузил его с проверкой ошибок и ничего не выдается, так что с механикой все в порядке, но где-то в цикле есть логическая проблема, которую я не могу идентифицировать.

Вот репозиторий: https://gitlab.com/IrateSwami/c_pipes/tree/dev

Пример выполнения:

1234567 102 08/11/18 4.00
1234567 101 08/14/18 14.00
3456787 9873 08/30/18 100.00
1234567 100 08/16/18 35.00
3456787 9874 09/30/18 4.00
12345 1010 09/01/18 34.00
1001001 905 08/14/18 9.00
1001001 903 08/30/18 11.00
12345 1001 09/14/18 16.00
12345 1111 08/24/18 2.00
12345 1112 08/31/18 44.00
1001001 902 09/25/18 19.00

Enter a command: add,1234567,999,01/01/01,99.99

Enter a command: list

Время выполнения, которое вызывает у меня проблемы с файлом slave.c:

// start the do-while loop for command stuff

// read in from the pipe
error_check = read(read_pipe, buffer, 1000);
if(error_check<0){
    perror("child process error, reading in from pipe");
    exit(-3);
}

// null terminate the end of buffer 
buffer[error_check] = '\0';

// here's where the command stuff starts 
char *first_command;
while(strcmp(first_command, "exit\n") != 0){
    // grab the first thing from the buffer, it'll be the command
    char *command = strtok(buffer, ",");
    first_command = command;
    printf("first command: %s\n", first_command);


    // now for the parameters
    int parameter_count = 0;
    char *parameters[4];

    while(command != NULL){
        command = strtok(NULL, ",");
        parameters[parameter_count] = command;
        parameter_count++;
    }

    // exit appropriately
    if(strcmp(first_command, "exit\n") == 0)
        return 9;

    // add a record
    else if(strcmp(first_command, "add") == 0){
        Record temp_record;
        temp_record.account_number = atoi(parameters[0]);
        temp_record.check_number = atoi(parameters[1]);
        temp_record.amount = atof(parameters[3]);
        strcmp(temp_record.transaction_date, parameters[2]);

        records[record_count] = temp_record;
        record_count++;

        error_check = write(write_pipe, "add completed", strlen(buffer));
        if(error_check<0){
            perror("error writing in add function");
            exit(-6);
        }
    }

    // delete a record
    else if(strcmp(first_command, "delete") == 0){
        for (int i = 0; i < record_count; i++){
            if(
            atoi(parameters[0]) == records[i].account_number && 
            atoi(parameters[1]) == records[i].check_number){

                records[i].account_number = 0;
                records[i].check_number = 0;
                records[i].amount = 0.0;
                strcpy(records[i].transaction_date, "\0");

            }
        }
    }

    // list all the records contained
    else if(strcmp(first_command, "list\n") == 0){

        // write all the records to the buffer 
        position = 0;
        for(int i = 0; i < record_count; i++){
            position += sprintf(buffer+position, "%d %d %s %.2f\n", 
            records[i].account_number,
            records[i].check_number,
            records[i].transaction_date,
            records[i].amount);
        }

        printf("%s\n", buffer);

        // write the buffer to the pipe
        error_check = write(write_pipe, buffer, strlen(buffer));

        // check for errors
        if(error_check<0){
            perror("child process write error");
            exit(-4);
        }

        // make sure the length of the buffer was proper
        if(error_check!=strlen(buffer)){
            printf("child process error, buffer was a weird size\n");
            exit(-5);
        }
    }

    else{
        printf("you didn't input a correct command\n");
    }


    // empty out everything for reuse
    strcpy(buffer, "\0");
    command = "\0";
    first_command = "\0";
    for(int i = 0; i < 4; i++)
        parameters[i] = "\0";

    // grab the new command 
    error_check = read(read_pipe, buffer, 1000);
    if(error_check<0){
        perror("child process error, reading in from pipe");
        exit(-5);
    }

    // null terminate the end of buffer 
    buffer[error_check] = '\0';

    printf("end of child do while buffer: %s\n", buffer);

}

1 Ответ

0 голосов
/ 06 октября 2018

Во-первых, мы можем заметить, что то, что должен выводить дочерний элемент (раб), не появляется на экране после того, как ему была отправлена ​​первая команда (add ...).

Во втором приглашениидля команды, если вы остановите свою программу и выполните ps, вы заметите, что ребенок мертв:

$ ps
  PID TTY          TIME CMD
27069 pts/29   00:00:00 master
27070 pts/29   00:00:00 slave <defunct>

Одной из основных проблем в подчиненном является то, что вы сравниваете first_command, чтоне инициализирован, чтобы «выйти».Это сравнение требует, чтобы байты по адресу first_command были доступны.Если этот адрес равен NULL или, в более общем случае, находится за пределами вашего программного пространства, вы получаете ошибку сегментации, которая убивает дочернего элемента.

Как это стало незаметным для родительского процесса?Потому что, когда вы read из канала, вы проверяете только ошибки, а не EOF (0), что означает, что канал пуст и закрыт (IOW, дочерний элемент мертв).

Исправление: инициализируйте вашпеременная

char *first_command = "";

(или лучше, используйте цикл do...while)

Есть и другие незначительные проблемы в вашем коде, некоторые из которых уже были сообщены вам в комментариях, некоторые появляются ясно, когдакомпиляция с -Wall (всегда используйте этот флаг и исправляйте предупреждения), другие ожидают вашей проницательности; -)

...