无法从 C 管道读取多个结构类型消息

问题描述

我正在尝试开发一个程序,该程序将启动 2 个子进程来运行,这些子进程将读取一个目录中的所有文件并将信息传递给另一个子进程以在另一个目录中创建这些文件。 下面是我的代码。但是我无法从管道中读取消息。如果我传递一个硬编码的字符串对象,我就可以从管道中读取它。但不是我试图传递的结构对象。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>  //Header file for sleep(). man 3 sleep for details.
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>

#define BUF_SIZE 1024

// Struct to store the file name and content
struct FileDetails{
    char *file_name;
    char *file_content;
};


// Helper function to create file at a given path and with given content.
void * createFile(struct FileDetails fileDetail){
int status;
   FILE *fptr;

   fptr = fopen(fileDetail.file_name,"a");

   if(fptr == NULL)
   {

      perror("Error!");   
      return NULL;          
   }

   fprintf(fptr,"%s",fileDetail.file_content);
   fclose(fptr);
   return NULL;
}

//Helper function used to copy two strings into one and return new string
char* strAppend(char* str1,char* str2){
        char * new_str ;
        if((new_str = malloc(strlen(str1)+strlen(str2)+1)) != NULL){
            new_str[0] = '\0';   // ensures the memory is an empty string
            strcat(new_str,str1);
            strcat(new_str,str2);
        } else {
            printf("%s","malloc Failed!\n");
            // exit?
        }
    return new_str;
}


// Each child will execute this helper funtion. It takes one argument which is the location of the directory to read all files from and send data to other child.
// Second argument is the pipe where we write
void *threadUtility(void *vargp,int* fd1)
{
    // Store directory pointer
    DIR* directoryPtr;
    // Store file pointer
    FILE *entry_file;
    struct dirent *current_file;
    int i;

    char* directory = (char *)vargp;
    printf("Process started for directory: %s\n",directory);
    directoryPtr = opendir(directory);

    if(directoryPtr==NULL) {
        printf("Error! Unable to read directory: %s\n",directory);
        exit(1);
    }

    close(fd1[0]);  // Close reading end of first pipe

    while((current_file=readdir(directoryPtr)) != NULL) {
        if (!strcmp (current_file->d_name,"."))
            continue;
        if (!strcmp (current_file->d_name,".."))
            continue;
        struct FileDetails fileDetail;
        fileDetail.file_name = malloc(strlen(current_file->d_name) + 1);

        fileDetail.file_name = current_file->d_name;

        // Appending directory path to file name to read contents
        char * new_str = strAppend(directory,current_file->d_name);
        //printf("FileName FQN: %s\n",fileDetail.file_name);

        entry_file = fopen(new_str,"r");
        struct stat sb;
        stat(new_str,&sb);

        char *file_contents = malloc(sb.st_size);
        fileDetail.file_content = malloc(sb.st_size);
        if (entry_file != NULL) {
            //Looping through each line of file to read all lines.
            while (fscanf(entry_file,"%[^\n] ",file_contents) != EOF) {
                fileDetail.file_content = strAppend(fileDetail.file_content,file_contents) ;
                fileDetail.file_content = strAppend(fileDetail.file_content,"/n") ;
            }
        } else{
            perror("Failed: ");
            exit(1);
        }
    fclose(entry_file);
    //printf("Writing to pipe: %s\n",fileDetail.file_name);

    if (write(fd1[1],&fileDetail,sizeof(struct FileDetails)) < 0) {
                printf("error writing");
    }
    }

    close(fd1[1]);
    closedir(directoryPtr);
    printf("Process ended for directory: %s\n",directory);
    return NULL;
}

// This program takes two command line argument which are direectory paths of two location.   
int main( int argc,char *argv[] )
{
    // If 2 paths not provided the program will terminate
    if( argc != 3 ) {
      printf("Provide two directory paths:  %i\n",argc);
      exit(1);
   }
    
    //Pipes for communication
    int fd1[2];  // Used to store two ends of first pipe
    int fd2[2];  // Used to store two ends of second pipe
    //Create pipes
    if (pipe(fd1)==-1)
    {
        fprintf(stderr,"Pipe Failed" );
        return 1;
    }
    if (pipe(fd2)==-1)
    {
        fprintf(stderr,"Pipe Failed" );
        return 1;
    }

   // Process ids for two child processes
    pid_t dir_one_child_process,dir_two_child_process;
    dir_one_child_process = fork();
    if (dir_one_child_process == 0) {
        /* Child One Process */
        threadUtility(strAppend(argv[1],"/"),fd1);
        wait(NULL);            
        // Reading messages sent by 2nd child
        close(fd2[1]); // Close writing end of second pip  
        // Read string from child,print it and close
        // reading end.
        struct FileDetails readForSecond;
        int n_bytes;
            while (read(fd2[0],&readForSecond,sizeof(&readForSecond)) > 0) {
                printf("From Child One: %s\n",readForSecond.file_name);
                // Here you have to call the createFile function in order to create the file once you get the FileDetail object
                //I'm stuck here
                //sleep(1);
                }
        printf("From Child Two: %s\n",readForSecond.file_name);
        close(fd2[0]);
    } else {
        dir_two_child_process = fork();

        if (dir_two_child_process == 0) {
            /* Child Two Process */

            close(fd1[1]);  // Close writing end of first pipe
            struct FileDetails readForFirst;
            int n_bytes;
            while (read(fd1[0],&readForFirst,sizeof(&readForFirst)) > 0) {
                printf("From Child One file_name: %s\n",readForFirst.file_name);
                // Here you have to call the createFile function in order to create the file once you get the FileDetail object
                //I'm stuck here
                //sleep(1);
                }
                                printf("reading ends:");

            // Close both reading ends
            close(fd1[0]);
            threadUtility(strAppend(argv[2],fd2);
        } else {
                /* Parent Code waiting for two childs to end*/
                waitpid(dir_one_child_process,NULL,0);
                waitpid(dir_two_child_process,0);            
            printf("Main Function Ends. Exiting\n");
        }
    }
    exit(0);
} 

解决方法

这是一个错误:

write(fd1[1],&fileDetail,sizeof(struct FileDetails))

sizeof(struct FileDetails)不是您使用 fileDetail 中的指针存储的数据的大小。由于 struct FileDetails

struct FileDetails{
    char *file_name;
    char *file_content;
};

它只是两个指针的大小(通常是 2x4 或 2x8)。

您可以使用以下方法检查尺寸:

printf("%zu\n",sizeof(struct FileDetails));

所以看起来好像你发送了两个指针值而不是文件的内容。那不是你想要的。

此外,这是错误的:

read(fd2[0],&readForSecond,sizeof(&readForSecond))
                             ^^^^^^^^^^^^^^^^^^^^^
                             This is size-of a single pointer