Передача структуры с двумя динамическими массивами через канал и разветвление

#c #fork #pipe

#c #разветвление #канал

Вопрос:

У меня есть домашнее задание для университета. Моя домашняя работа состоит в том, чтобы создать проект с использованием fork и использовать метод конвейерной обработки для передачи данных через дочерние и родительские процессы. Ну, нам нужно создать два канала. 1-й канал отправляет текстовый файл, в который вы запишете результат «Ps -A», а 2-й канал вернет pid и их приоритеты. Профессор сказал, что мы должны использовать динамические массивы и через структуру мы должны передать массив pid и массив ppid обратно дочернему элементу.Дочерний элемент выводит оба массива на экран. Проблема, с которой я сталкиваюсь, в том, что дочерние элементы заполняют массивы, здесь все хорошо, но когда я отправляю их отцу, отец не просто считывает массивы из struct и ничего не выводит на экран : ( можете ли вы помочь мне с этим?

     struct dyna {
        int *pids;
        int *ppids;
    };

    int main(int argc, char *argv[]){
        int child_id;
        int pipe_pc[2],pipe_cp[2];
        int result_pc,result_cp;
        int lines1,i;

        if (argc!=2)//elegxos gia to an ta arguments pou edwse o xristis einai arxeio1 arxeio2 {
            fprintf(stderr,"Lathos arithmos orismaton.To swsto einai %s filename.txtn",argv[0]);
            exit(1);
        } else {
            result_pc=pipe(pipe_pc);
            if (result_pc==-1) exit(-1);
            result_cp=pipe(pipe_cp);
            if (result_cp==-1) exit(-1);

            struct dyna dyn;    

            child_id=fork();
            if (child_id==-1) exit(-1);
            //child
            if (child_id==0){
                char child_read_msg[buff];

                close(pipe_pc[1]);
                memset(child_read_msg,0,buff);
                read(pipe_pc[0],child_read_msg, buff);

                printf("nchild process:child read from father: %sn",child_read_msg);

                char child_write_msg[buff]="lol",lines[buff]="lines.txt",* pch,**grammes;
                FILE *pFile1,*pFile2;
                long lSize1,lSize2;
                char *buffer1,*command,*buffer2;
                size_t file1str,file2str;

                command = (char*)malloc(strlen("wc -l >") strlen(child_read_msg) strlen(lines));
                sprintf(command,"ps -A> %s",child_read_msg);
                system(command);

                //vazoume ta periexomena tou processes.txt se enan buffer
                pFile1 = fopen ( child_read_msg, "rb" ); 
                fseek (pFile1, 0 , SEEK_END);
                lSize1 = ftell (pFile1);
                rewind (pFile1);
                buffer1 = (char*) malloc (sizeof(char)*lSize1);
                if (buffer1 == NULL) {fputs ("Memory error",stderr); }
                file1str = fread (buffer1,1,lSize1,pFile1);
                if (file1str != lSize1) {fputs ("Reading error",stderr); }
                fclose(pFile1);


                //vriskoume ton arithmon grammon tou arxeiou
                sprintf(command,"wc -l %s>%s",child_read_msg,lines);
                system(command);

                pFile2 = fopen ( lines, "rb" ); 
                fseek (pFile2, 0 , SEEK_END);
                lSize2 = ftell (pFile2);
                rewind (pFile2);

                buffer2 = (char*) malloc (sizeof(char)*lSize1);
                if (buffer2 == NULL) {fputs ("Memory error",stderr); }
                file2str = fread (buffer2,1,lSize2,pFile2);
                if (file2str != lSize2) {fputs ("Reading error",stderr); }
                fclose(pFile2);
                sscanf(buffer2,"%d",amp;lines1); //lines1= arithmos grammon tou processes.txt
                sprintf(command,"rm -r %s",lines);
                system(command);
                free(buffer2);

                i=0;
                dyn.pids=(int *)calloc(sizeof(int),lines1); //desmeuei mnimi dinamika gia ton proto pinaka tis struct pou periexei ta pid
                pch = strtok (buffer1,"n");
                while (pch != NULL){
                    sscanf(pch,"%d",amp;dyn.pids[i]);
                    pch = strtok (NULL, "n");
                    i  ;
                }


                dyn.ppids=(int *)calloc(sizeof(int),lines1);
                for (i=1;i<lines1;i  ) /*Gemizei ton pinaka kai vazei tis proteraiotites tis kathe diergasias */ {
                    dyn.ppids[i]=getpriority(PRIO_PROCESS,dyn.pids[i]);
                }

                //for (i=1;i<lines1;i  ){
                //printf("%dn",dyn.ppids[i]); 
                //}

                close(pipe_cp[0]);
                write(pipe_cp[1], amp;dyn,sizeof(dyn));

            }
            //parent
            else {
                close(pipe_pc[0]);
                write(pipe_pc[1], argv[1],strlen(argv[1]));
                printf("nparent process: father wrote to child: %sn",argv[1]);

                wait(NULL);

                close(pipe_cp[1]);//kleinoume to write-end, o pateras mono diabazei apo to pipe_cp
                read(pipe_cp[0],amp;dyn,sizeof(dyn));//parent diabazei ayto poy exei grapsei to paidi
                //prints the array with the priorities of the processes
                for (i=1;i<lines1;i  ){
                    printf("%dn",dyn.ppids[i]);
                }

            }
            return 0;
        }
    }
  

Ответ №1:

write(pipe_cp[1], amp;dyn,sizeof(dyn)) просто передает два указателя из вашей структуры, а не фактические данные, на которые они ссылаются. Адреса, которые содержат эти указатели, были бы бессмысленны в родительском процессе, поскольку у него есть отдельное адресное пространство. Разыменование их там вызовет неопределенное поведение, скорее всего, ошибку сегментации.

Если вы хотите, чтобы ваш код работал таким образом, вам нужно объявить члены структуры массивами фиксированного размера, а не указателями. При этом структура по существу становится контейнером, который содержит в себе два массива.

Комментарии:

1. Ну, я сделал массивы статическими… но все еще ничего не смог получить от родительского элемента после прочтения структуры из канала : ( Кажется странным, но я снова увижу, что пошло не так : (

Ответ №2:

Существует хорошая библиотека для сериализации структур и массивов C, называемая tpl. Я использую это довольно долгое время, и я вполне доволен этим.

Возможно, вы захотите взглянуть на это и посмотреть, как они это делают.

Примеры с веб-сайта с использованием файлов (не ограничиваясь файлами, должны работать на всем, что может выполнять передачу сообщений):

 /* Storing ids and usernames */
#include <tpl.h>

int main(int argc, char *argv[]) {
    tpl_node *tn;
    int id=0;
    char *name, *names[] = { "joe", "bob", "cary" };

    tn = tpl_map("A(is)", amp;id, amp;name);

    for(name=names[0]; id < 3; name=names[  id]) {
        tpl_pack(tn,1);
    }

    tpl_dump(tn, TPL_FILE, "users.tpl");
    tpl_free(tn);
}
  

И наоборот:

 /* Reloading ids and usernames */
#include <tpl.h>

int main(int argc, char *argv[]) {
    tpl_node *tn;
    int id;
    char *name;

    tn = tpl_map("A(is)", amp;id, amp;name);
    tpl_load(tn, TPL_FILE, "users.tpl");

    while ( tpl_unpack(tn,1) > 0 ) {
        printf("id %d, user %sn", id, name);
        free(name);
    }
    tpl_free(tn);
}
  

Другой альтернативой было бы кодирование и декодирование в ASN.1 вместо создания вашей собственной кодировки. Кроме того, вы могли бы получить коричневые очки за соблюдение стандартов.