如何为n个子进程实现n个管道

时间:2018-03-07 22:01:51

标签: c pipe child-process

我有这个代码,据说创建了n个子节点和n个管道(作为主要参数给出了n),我想要做的是使用方便的管道读取/发送一个char *到指定的子节点写系统调用,它实际上没有工作(我是系统编程的新手)

这是主要的

int main(int argc, char const *argv[])
{
int tmp,np;
int tube[MAX_PROCESS][2], i;
pid_t pid[MAX_PROCESS];
char *chaine;


if(argc != 2){
    perror("Error : nombre d'arguments est invalide\n");
    exit(EXIT_FAILURE);
}

tmp = atoi(argv[1]);

if(tmp > 10){
    fprintf(stderr,"Erreur : nombre de processus fils doit étre inférieure a %d", MAX_PROCESS);
    exit(EXIT_FAILURE);
}
for(i=0;i<tmp;i++){
    if(pipe(tube[i]) == -1){
        perror("Erreur lors du création du tube");
        exit(EXIT_FAILURE);
    }
}
printf("fermeture des tubes de lecture dans le pere\n");

for(i=0; i < tmp; i++){

            if(close(tube[i][TUBE_LECTURE]) == -1){
                fprintf(stderr,"Erreur lors la fermeture de tube de lecture %d\n",i);
                exit(EXIT_FAILURE);
            }else
                printf("tube %d fermé\n", i);
}


printf("lecture a partir du clavier d'une chaine et du numéro du fils voulu : \n");

chaine = (char*) malloc(sizeof(char));

if(scanf("%s %d", chaine, &np) != 2){
    perror("Erreur de lecture de la chaine ou du numéro du processus fils\n");
    exit(EXIT_FAILURE);
}


printf("création des fils...\n");

for(i=0; i<tmp; i++){
    if((pid[i] = fork()) == -1){
        perror("Erreur lors du création des fils");
        exit(EXIT_FAILURE);
    }
}


printf("Initialisation fonction 'fils'\n");
for(i=0;i<tmp;i++) {
    if(pid[i] == 0)
        fils(np,tmp,tube);
}

printf("ecriture dans le tube\n");

if(write(tube[np][TUBE_ECRITURE],chaine,sizeof(chaine)) == -1){
    perror("Erreur ecriture dans le tube\n");
    exit(EXIT_FAILURE);
}

/*fermeture des tubes d'écriture*/

for(i=0; i< tmp; i++){
    if(close(tube[i][TUBE_ECRITURE]) == -1){
        perror("Erreur lors la fermeture de tube de l'écriture\n");
        exit(EXIT_FAILURE);
    }
}

/*attente des fils*/

for(i=0;i<tmp;i++){
    if(waitpid(pid[i],NULL, 0) == -1){
        fprintf(stderr,"Erreur lors de l'attente du fils %d",i);
        exit(EXIT_FAILURE);
    }
    else
        printf("le fils %d a terminé\n", i);
}

printf("tous les fils ont terminé\n");


return EXIT_SUCCESS;
}

它打印出以下错误:

  fermeture des tubes de lecture dans le pere
  tube 0 fermé
  tube 1 fermé
  tube 2 fermé
  tube 3 fermé
  lecture a partir du clavier d'une chaine et du numéro du fils voulu : 
  yassine
  2
  création des fils...
  Initialisation fonction 'fils'
  ecriture dans le tube
  Initialisation fonction 'fils'
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Initialisation fonction 'fils'
  Erreur lors de la lecture Bad file descriptor
  Erreur lors de la lecture Bad file descriptor

1 个答案:

答案 0 :(得分:0)

你有很多概念错误。

  1. 在执行fork之前,无法关闭管道的读取端。该 孩子继承父母的文件描述符的状态,你必须 fork,然后在父过程中关闭管道的阅读端

  2. 当您使用fork时,您必须为子进程和代码编写代码 parent进程。你不这样做,但不是在正确的地方。你做了

    printf("création des fils...\n");
    
    for(i=0; i<tmp; i++){
        if((pid[i] = fork()) == -1){
            perror("Erreur lors du création des fils");
            exit(EXIT_FAILURE);
        }
    }
    

    在这里,你正在创造出许多孩子,孩子和执行的方式 fork在接下来的迭代中,你最终不会有几个孩子,但是有一个 全军儿童。根据{{​​1}}的大小,您可能会消耗所有内容 tmp允许进程。只有父母应该在您的情况下执行fork (见下面的代码)。

  3. 此代码:

    fork

    should not cast malloc,此处您正在为一个分配空间 charcter,为什么甚至懒得为单个字符动态分配内存。 然后在chaine = (char*) malloc(sizeof(char)); if(scanf("%s %d", chaine, &np) != 2){ perror("Erreur de lecture de la chaine ou du numéro du processus fils\n"); exit(EXIT_FAILURE); } 中使用来读取字符串。这会溢出缓冲区,因为 一个字符串是scanf - 终止,甚至对于长度为1的字符串,你需要2 空格。

  4. 我真的不明白'\0'的含义是什么,但稍后你会这样做

    np

    但是您永远不会检查if(write(tube[np][TUBE_ECRITURE],chaine,sizeof(chaine)) == -1){ 是否在[0 - np]范围内,您可以访问 管道数组越界。

  5. 下面

    MAX_PROCESS

    if(write(tube[np][TUBE_ECRITURE],chaine,sizeof(chaine)) == -1){ 给出指针的大小,但是如果尝试发送字符串, 你应该写sizeof(chaine)个字节,strlen(chaine)+1用于+1 - 终止 字节,否则管道另一边的孩子不知道有多少 它应该为字符串读取的字节数。

  6. \0只应在函数返回错误值并设置时使用 perror。在代码的开头,如果errno,则不会设置 使用argc != 2 errno到任何值都会打印出错误的错误消息。您 应改为使用perror

  7. 所以这是一个版本(没有fprintf(stderr, "...函数,因为我不知道它是什么 这会告诉你如何fils并通过管道发送数据。

    fork

    具有此输出:

    #include <stdio.h>
    #include <sys/types.h>
    #include <signal.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/wait.h>
    #include <string.h>
    
    #define MAX_PROCESS 5
    
    int child_process(int id, int tube[2], int np)
    {
        int ret = 0;
        char buffer[100] = {0};
        printf(" Child %d, attempt to read 100 characters from parent. np is: %d\n", id, np);
    
        // closing writing end
        close(tube[1]);
    
        ssize_t size = read(tube[0], buffer, sizeof buffer);
    
        if(size <= 0)
        {
            printf(" Child %d, could not read from parent\n", id);
            ret = 1;
        } else {
            // making sure to \0-terminate string
            if(buffer[size] != 0)
                buffer[size - ( size == sizeof(buffer) ? 1 : 0)] = 0;
            printf(" Child %d: parent sent '%s'\n", id, buffer);
        }
    
        // closing reading end
        close(tube[0]);
    
        return ret;
    }
    
    int main(int argc, char **argv)
    {
        int tube[MAX_PROCESS][2], i;
        pid_t pid[MAX_PROCESS];
    
        if(argc != 2){
            fprintf(stderr, "Error : nombre d'arguments est invalide\n");
            exit(EXIT_FAILURE);
        }
    
    
        int noc = atoi(argv[1]);
    
        if(noc <= 0 || noc > MAX_PROCESS)
        {
            fprintf(stderr, "Erreur : nombre de processus fils doit étre inférieure a %d", MAX_PROCESS);
            exit(EXIT_FAILURE);
        }
    
        printf("lecture a partir du clavier d'une chaine et du numéro du fils voulu : \n");
    
        char chaine[100];
        int np;
    
        if(scanf("%99s %d", chaine, &np) != 2)
        {
            fprintf(stderr, "Erreur de lecture de la chaine ou du numéro du processus fils\n");
            exit(EXIT_FAILURE);
        }
    
        if(np < 0 || np >= MAX_PROCESS)
        {
            fprintf(stderr, "Error: np must be in range [0 - %d]\n", MAX_PROCESS-1);
            exit(EXIT_FAILURE);
        }
    
        printf("création des fils...\n");
    
    
        for(i = 0; i < noc; ++i)
        {
            if(pipe(tube[i]) == -1)
            {
                perror("pipe");
                exit(EXIT_FAILURE);
            }
    
            pid[i] = fork();
    
            if(pid[i] == -1)
            {
                perror("fork");
                exit(EXIT_FAILURE);
            }
    
            if(pid[i] == 0)
            {
                // CHILD PROC
                exit(child_process(i, tube[i], np));
            }
    
            // PARENT PROC
            // closing reading end
            close(tube[i][0]);
        }
    
        // parent sends data to children
        for(i = 0; i < noc; ++i)
        {
            size_t len = strlen(chaine) + 1;
            if(write(tube[i][1], chaine, len) != len)
                fprintf(stderr, "Parent could not send the whole string to the child %d\n", i);
    
            // closing writing pipe
            close(tube[i][1]);
        }
    
        for(i = 0; i < noc; ++i)
        {
            if(waitpid(pid[i],NULL, 0) == -1){
                fprintf(stderr,"Erreur lors de l'attente du fils %d\n",i);
                exit(EXIT_FAILURE);
            }
            else
                printf("le fils %d a terminé\n", i);
        }
    
    
        exit(EXIT_SUCCESS);
    }