使用管道分享共享内存发出读写文件

时间:2017-04-06 16:03:24

标签: c linux pipe fork shared-memory

我正在尝试在C中使用管道。我有两个在父进程和子进程之间创建两个管道。我必须读取一个4096字节的文件(如果有更少的话,则更小),我必须通过管道读取的数据量和读数的次数。例如,要复制6KB文件,父级会将文件的前4KB数据写入共享内存,并通过管道向子级发送两个整数1和4096。子进程接收这两个数字,从共享内存复制4096个字节到输出文件,并通过另一个管道将1发送回父进程。收到1后,父级将左侧2KB数据复制到共享内存,并将2和2048发送给子级。子进程从管道接收它们,将2048个字节复制到输出文件,并用2回复父进程。父母然后向孩子发送0,0。孩子收到0并回复0然后退出。父母收到0并退出。

目前我的程序适用于少于一个块的文件,但不适用于大于一个块(4096字节)的文件

697,谢谢你的指出,我已经修改了我的程序如下但仍有问题,基本上如何控制流程为父子父母...

#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

#define SIZE 4096



int file_exist (char *filename)
{
  struct stat   buffer;
  return (stat (filename, &buffer) == 0);
}




int main(int argv, char *argc[]) {


    /*Check if program is called correctly*/
    if(argv != 3) {
    printf("Please call program appropriately\n");
    exit(EXIT_FAILURE);
    }

    FILE *r, *w;
    void *sharedMem;
    int datapipe[2];
    int blockpipe[2];
    int shm;
    char userInput[5];
    char *name = "fsuid_cop4610";

    if (file_exist (argc[2]))
    {
        printf("Would you like to overwrite file (yes/no): ");
        scanf("%s", userInput);
        if(!strcmp(userInput, "yes")) {
            printf("Overwriting file...\n");
            //fclose(w);
            w = fopen(argc[2], "wb");
            if(w == NULL) {
                perror("Error with write file");
                exit(EXIT_FAILURE);
            }
        }
        else if(!strcmp(userInput, "no")) {
            printf("Will not overwrite\n");
            exit(EXIT_FAILURE);
        }
        else {
            printf("User input not accepted\n");
            exit(EXIT_FAILURE);
        }
    }

    /*Check if read file can open*/
    r = fopen(argc[1], "rb");
    if(r == NULL)  {
        perror("Error opening read file");
        exit(EXIT_FAILURE);
    }
    fseek(r, 0, SEEK_END); // seek to end of file
    int inputlength = ftell(r); // get current file pointer
    printf("inputlength is %d\n",inputlength);
    int numofblock = inputlength/SIZE + 1;
    fseek(r, 0, SEEK_SET); // seek back to beginning of file
    /*Check if write file can open*/





    if (pipe(datapipe) < 0) {
        perror("Pipe");
        exit(EXIT_FAILURE);
    }

    if (pipe(blockpipe) < 0) {
        perror("Pipe");
        exit(EXIT_FAILURE);
    }


    /*Check if forking process is successful*/
    pid_t pid = fork();
    if(pid < 0) {
        perror("Fork");
        exit(EXIT_FAILURE);
    }

    shm = shm_open(name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
    if(shm == -1) {
        perror("Shared memory");
        exit(EXIT_FAILURE);
    }
    if(ftruncate(shm, SIZE) == -1) {
        perror("Shared Memory");
        exit(EXIT_FAILURE);
    }

    sharedMem = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm, 0);
    if(sharedMem == MAP_FAILED) {
        perror("Mapping shared memory");
        exit(EXIT_FAILURE);
    }

    if (pid>0) {    // parent
        printf(" parent before close data0,block1\n");
        close(datapipe[0]); // close read, will write data
        close(blockpipe[1]);    // close write, will read block number
        printf(" parent close data0,block1\n");
        for (int i=1; i<=numofblock; i++)
        {
            printf("... parent process\n");


            int blocknumber=i;

            printf("parent read from input file into shared memory\n");
            int P2SHM = fread(sharedMem, 1, SIZE, r);
            if(P2SHM < 0) {
                perror("Could not store to shared memory");
                exit(EXIT_FAILURE);
            }
            //printf("parent shared memory conent: %s\n",(char *)sharedMem);
            printf("parent data read %d\n",P2SHM);


            if (i==1)
            {
                printf("i=%d parent write to data pipe\n",i);
                if(write(datapipe[1], &P2SHM, sizeof(int)) < 0) {
                    perror("parent failed to write to pipe bytes");
                    exit(EXIT_FAILURE);
                }

                if(write(datapipe[1], &blocknumber, sizeof(int)) < 0) {
                    perror("parent failed to write to pipe block number");
                    exit(EXIT_FAILURE);
                }
            }


            printf("parent read from block pipe\n");

            int C2P = read(blockpipe[0], &blocknumber, sizeof(int));

            if(C2P < 0) {
                perror("parent failed to read value from blockpipe");
                exit(EXIT_FAILURE);
            }
            /*else if(C2P == 0) {
                printf("End of file reached\n");
            }*/
            else {
                printf("parent block %d Received succesfully\n", blocknumber);
                if (i>= 2)
                {
                    printf("i=%d parent write to data pipe\n",i);
                    //close(datapipe[0]);   // close read, will write data
                    if(write(datapipe[1], &P2SHM, sizeof(int)) < 0) {
                        perror("parent failed to write to pipe bytes");
                        exit(EXIT_FAILURE);
                    }

                    if(write(datapipe[1], &blocknumber, sizeof(int)) < 0) {
                        perror("parent failed to write to pipe block number");
                        exit(EXIT_FAILURE);
                    }
                    //close(datapipe[1]);
                }
                if(C2P == 0) {
                    printf("parent End of file reached\n");
                }

            }

        }   // end for
        printf(" parent before close data1,block0\n");
        close(datapipe[1]);
        close(blockpipe[0]);
        printf(" parent close data1,block0\n");
        printf(" ... existing parent process\n");

    }
    else {  // pid=0 child
        printf(" child before close data1,block0\n");
        close(datapipe[1]); // close write, will read data
        close(blockpipe[0]);    // close read, will write block number

        printf(" child close data1,block0\n");
        for (int j=1; j<=numofblock; j++)
        {
            printf(".... child process\n");



            int cBytes, len, len2;
            int blocknumber = 1;
            printf("child read from datapipe\n");

            len = read(datapipe[0], &cBytes, sizeof(cBytes));
            len2 = read(datapipe[0], &blocknumber, sizeof(blocknumber));

            printf("child wrote to blockpipe blocknumber=%d\n", blocknumber);

            write(blockpipe[1], &blocknumber, sizeof(blocknumber));

            printf("child There are %i bytes\n", cBytes);
            if(len >= 0)
            {
                printf("child writing to file\n");
                //fwrite(sharedMem, 1, sizeof(sharedMem), w);
                //printf("child shared memory conent: %s\n",(char *)sharedMem);
                char* res = (char *)sharedMem;
                //printf("res = %s\n",res);
                //printf("errno before write=%d",errno);
                shm_unlink(name);
                //int writtenbyte = fwrite(res, sizeof(char), strlen(res), w);
                int writtenbyte = fwrite(res, sizeof(char), cBytes, w);
                if(errno == EINTR) {
                    printf("somewhting wrong");
                }
                //printf("errno after write=%d",errno);
                printf("writtenbyte = %d\n",writtenbyte);
                //fclose(w);
                //fputs((char *)sharedMem, w);
                //fwrite(s->name, sizeof(char), strlen(s->name) + 1, fp);
            }
            /*else if (len == 0) {
              printf("End of fle reached\n");
            }*/
            else  {     // len < 0
              perror("Failed to read from pipe");
              exit(EXIT_FAILURE);
            }

        }   // after for
        printf(" child before close data0,block1\n");
        close(datapipe[0]);
        close(blockpipe[1]);
        printf(" child close data0,block1\n");
        printf("... exiting Child process\n");

    }
//shm_unlink(name);
//fclose(r);
fclose(w);
return 0;
}

结果:

输入长度为4177  关闭data0之前的父级,block1  parent close data0,block1 ......父进程 parent从输入文件读入共享内存 父数据读4096 i = 1父写入数据管道 父节点从块管读取  关闭data1之前的子节点,block0  child close data1,block0 ....儿童过程 孩子从datapipe读取 child写到blockpipe blocknumber = 1 child有4096个字节 孩子写到文件 父块1成功收到 ......父进程 parent从输入文件读入共享内存 父数据读81 父节点从块管读取 父块2成功收到 i = 2父写入数据管道

注意子写入块号为1,但是父节点接收到块号1,然后接收到块号2,并且从父节点开始第二次写入后停止,而不写入输出文件。有什么想法吗?

0 个答案:

没有答案