2011-10-28 7 views
6

J'essaie de faire une simple fourche -> exécuter un autre programme -> dire "bonjour" à ce processus enfant -> relire quelque chose -> imprimer ce que reçu.C: dup2, pipe et fork ne fonctionnant pas comme prévu

Le programme utilisé en tant qu'enfant attend juste n'importe quelle ligne d'entrée et imprime quelque chose à la sortie stdout comme "bonjour là!"

Ceci est mon "hôte" du programme (qui ne fonctionne pas):

#include <sys/types.h> 
#include <unistd.h> 
#include <stdio.h> 

#define IN 0 
#define OUT 1 
#define CHILD 0 

main() 
{ 
    pid_t pid; 
    int pipefd[2]; 
    FILE* output; 
    char buf[256]; 

    pipe(pipefd); 

    pid = fork();  
    if (pid == CHILD) 
    { 
    printf("child\n"); 
    dup2(pipefd[IN], IN); 
    dup2(pipefd[OUT], OUT); 
    execl("./test", "test", (char*) NULL); 
    } 
    else 
    { 
    sleep(1); 
    printf("parent\n"); 
    write(pipefd[IN], "hello!", 10); // write message to the process  
    read(pipefd[OUT], buf, sizeof(buf)); 
    printf("received: %s\n", buf); 
    } 
} 

Je reçois ceci:

child 
[.. waits 1 second ..] 
parent 
received: 

Qu'est-ce que je manque? Merci!

EDIT (test.c):

Sur demande, c'est le programme des enfants:

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

int getln(char line[]) 
{ 
    int nch = 0; 
    int c; 

    while((c = getchar()) != EOF) 
    { 
     if(c == '\n') break; 
    line[nch] = c; 
    nch++; 
    } 

if(c == EOF && nch == 0) return EOF; 
return nch; 
} 

main() 
{ 
    char line[20]; 

    getln(line); 
    printf("hello there!", line); 
    fflush(stdout); 
    return 0; 
} 

Répondre

3

Vous êtes toujours supposé lire le descripteur de fichier 0, et écrire au descripteur de fichier 1 avec des tuyaux ... vous avez cette relation est inversée dans le processus parent. Pour ce que vous voulez faire, vous pouvez avoir besoin de deux canaux pour une communication bidirectionnelle entre le parent et l'enfant, ce qui évite les situations où le parent finit par lire le contenu qu'il a écrit dans le tuyau puisque la planification du processus est non déterministe (c'est-à-dire que l'enfant n'a pas la garantie de lire ce que le parent a écrit dans le tube si le parent lit le même tube car le parent pourrait finir par écrire et ensuite lire sans entrelacer le processus fils pour lire ce que le parent a écrit).

Changer votre code à ce qui suit:

main() 
{ 
    pid_t pid; 
    int pipe_to_child[2]; 
    int pipe_from_child[2]; 
    FILE* output; 
    char buf[256]; 

    pipe(pipe_to_child); 
    pipe(pipe_from_child); 

    pid = fork();  
    if (pid == CHILD) 
    { 
    printf("child\n"); 

    //child process not using these ends of the pipe, so close them 
    close(pipe_to_child[1]); 
    close(pipe_from_child[0]); 

    dup2(pipe_to_child[0], fileno(stdin)); 
    dup2(pipe_from_child[1], fileno(stdout)); 

    execl("./test", "test", (char*) NULL); 
    } 
    else 
    { 
    sleep(1); 
    printf("parent\n"); 
    write(pipe_to_child[1], "hello!\n", 10); // write message to the process  
    read(pipe_from_child[0], buf, sizeof(buf)); 
    printf("received: %s\n", buf); 
    } 
} 
1

Vous devriez probablement utiliser wait ou waitpid.

1

Il semble que vos descripteurs de tuyau soient mélangés. Après l'appel pipe(), pipefd[0] est le lire fin du tuyau, et pipefd[1] est le écrire fin de la conduite. Vous écrivez à la fin de lecture, et lisez à partir de la fin d'écriture.

En outre, vous essayez d'utiliser un canal pour stdin et stdout du processus enfant. Je ne pense pas que ce soit vraiment ce que vous voulez faire (vous aurez besoin de deux pipes).

2

Vous avez besoin de deux tubes pour cela: un pour stdin du processus fils et un pour son stdout. Vous ne pouvez pas réutiliser les deux extrémités d'un tuyau comme deux tuyaux.

En outre, cette ligne du programme mère

write(pipefd[IN], "hello!", 10); // write message to the process  

ne pas écrire une nouvelle ligne, donc getln chez l'enfant ne reviendra plus. (En outre, "bonjour!" A seulement six caractères, mais vous écrivez dix.)

1

On dirait que vous avez votre IN/OUT en arrière pour la conduite - pipefd[0] est la fin lecture du tube, écrit ainsi (comme le parent ne) est absurde et échouera. De même, pipefd[1] est l'extrémité d'écriture, de sorte que sa lecture (comme le fait le parent) échouera également.Vous devriez toujours vérifier les valeurs de retour des appels en lecture et en écriture, pour voir si vous obtenez des erreurs

1

D'autres disent que le tuyau est mono-directionnel, ce que je pensais au début. Mais en réalité, ce n'est pas ce que ma page homme dit:

A read from fildes[0] accesses the data written to fildes[1] 
on a first-in-first-out (FIFO) basis and a read from 
fildes[1] accesses the data written to fildes[0] also on a 
FIFO basis. 

Cependant, cela ne signifie pas que si le parent est en train d'écrire à pipefd[0], l'enfant doit lire pipefd[1], de sorte que vous associez le mauvais côté de la conduite avec Stdin et stdout de l'enfant. À partir de la page de manuel, il semble que vous puissiez le faire avec un seul tuyau. Mais il pourrait être plus clair d'en utiliser deux.

Il semble que vous pensiez à chaque élément de pipefd comme un tuyau séparé, mais ce n'est pas le cas.

+0

[Selon la spécification POSIX] (http://pubs.opengroup.org/onlinepubs/009604599/functions/pipe.html) sur 'pipe', *" Il n'est pas spécifié si fildes [0] est également ouvert pour écrire et si fildes [1] est également ouvert à la lecture. "* – Jason

+0

Oui, si vous voulez un canal bidirectionnel garanti vous avez besoin de' socketpair' ou d'un pseudoterminal. – zwol

Questions connexes