Comment envoyer une simple chaîne entre deux programmes en utilisant des tubes?

111

J'ai essayé de chercher sur le net, mais il n'y a pratiquement pas de ressources. Un petit exemple suffirait.

EDIT Je veux dire, deux programmes C différents communiquant entre eux. Un programme doit envoyer "Salut" et l'autre doit le recevoir. Quelque chose comme ca.


la source
1
Vous ne voulez probablement pas dire quelque chose comme ls | grep ".o"? Peut-être qu'un peu plus d'explications sur ce que vous voulez dire aiderait ...
Jerry Coffin
13
Allez mec ... un petit effort. Google "c pipes example code". Le premier résultat est exact: tldp.org/LDP/lpg/node11.html
Stephen
4
Je veux une communication entre deux programmes complètement différents. Je n'ai pas pu trouver une ressource pour cela.
1
Si vous ne forgez pas un processus, vous devez regarder les "tubes nommés".
Juge Maygarden

Réponses:

156

Un tube normal ne peut connecter que deux processus associés. Il est créé par un processus et disparaîtra lorsque le dernier processus le fermera.

Un tube nommé , également appelé FIFO pour son comportement, peut être utilisé pour connecter deux processus non liés et existe indépendamment des processus; ce qui signifie qu'il peut exister même si personne ne l'utilise. Un FIFO est créé à l'aide de la mkfifo()fonction de bibliothèque.

Exemple

écrivain.c

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    int fd;
    char * myfifo = "/tmp/myfifo";

    /* create the FIFO (named pipe) */
    mkfifo(myfifo, 0666);

    /* write "Hi" to the FIFO */
    fd = open(myfifo, O_WRONLY);
    write(fd, "Hi", sizeof("Hi"));
    close(fd);

    /* remove the FIFO */
    unlink(myfifo);

    return 0;
}

lecteur.c

#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>

#define MAX_BUF 1024

int main()
{
    int fd;
    char * myfifo = "/tmp/myfifo";
    char buf[MAX_BUF];

    /* open, read, and display the message from the FIFO */
    fd = open(myfifo, O_RDONLY);
    read(fd, buf, MAX_BUF);
    printf("Received: %s\n", buf);
    close(fd);

    return 0;
}

Remarque: la vérification des erreurs a été omise du code ci-dessus pour plus de simplicité.

jschmier
la source
6
Qu'est-ce qui est considéré comme des processus connexes ?
Pithikos
7
Probablement des processus qui sont liés via une ou plusieurs relations parent / enfant (par exemple, les frères et sœurs). L'ancêtre commun aurait créé les deux extrémités du tuyau. Les processus non liés n'ont pas cet ancêtre commun.
MSalters
4
Cela ne fonctionnera pas si le lecteur démarre en premier. Une solution rapide serait de mettre open()le lecteur dans une boucle. Cependant +1 parce que vous fournissez un exemple de deux programmes.
gsamaras
Je suppose que cet exemple nécessite quelques ajustements pour fonctionner sur Windows? unistd.h étant POSIX et tout ...
David Karlsson
Oui, il faudra peaufiner Windows. L' article de Wikipédia sur les canaux nommés décrit certaines des différences Unix / Windows et une recherche rapide sur Google peut aider à l'implémentation Windows.
jschmier
41

Depuis la création de tubes en C , cela vous montre comment créer un fork d'un programme pour utiliser un tube. Si vous ne voulez pas fork (), vous pouvez utiliser des tubes nommés .

De plus, vous pouvez obtenir l'effet de prog1 | prog2en envoyant la sortie de prog1vers stdout et en lisant depuis stdinin prog2. Vous pouvez également lire stdin en ouvrant un fichier nommé /dev/stdin(mais pas sûr de la portabilité de celui-ci).

/*****************************************************************************
 Excerpt from "Linux Programmer's Guide - Chapter 6"
 (C)opyright 1994-1995, Scott Burkett
 ***************************************************************************** 
 MODULE: pipe.c
 *****************************************************************************/

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

int main(void)
{
        int     fd[2], nbytes;
        pid_t   childpid;
        char    string[] = "Hello, world!\n";
        char    readbuffer[80];

        pipe(fd);

        if((childpid = fork()) == -1)
        {
                perror("fork");
                exit(1);
        }

        if(childpid == 0)
        {
                /* Child process closes up input side of pipe */
                close(fd[0]);

                /* Send "string" through the output side of pipe */
                write(fd[1], string, (strlen(string)+1));
                exit(0);
        }
        else
        {
                /* Parent process closes up output side of pipe */
                close(fd[1]);

                /* Read in a string from the pipe */
                nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
                printf("Received string: %s", readbuffer);
        }

        return(0);
}
Stephen
la source
1
Hey Stephen, de toute façon je peux utiliser ce code pour deux fonctions différentes? ce qui signifie que l'écriture dans le tube se fait dans une fonction et la lecture du tube dans une autre fonction ?? un code de travail comme celui-ci serait apprécié.
Mohsin
8
dup2( STDIN_FILENO, newfd )

Et lis:

char reading[ 1025 ];
int fdin = 0, r_control;
if( dup2( STDIN_FILENO, fdin ) < 0 ){
    perror( "dup2(  )" );
    exit( errno );
}
memset( reading, '\0', 1025 );
while( ( r_control = read( fdin, reading, 1024 ) ) > 0 ){
    printf( "<%s>", reading );
    memset( reading, '\0', 1025 );
}
if( r_control < 0 )
    perror( "read(  )" );    
close( fdin );    

Mais je pense que cela fcntlpeut être une meilleure solution

echo "salut" | code
mlouk
la source
6

Ce qu'un programme écrit sur stdout peut être lu par un autre via stdin. Donc simplement, en utilisant c, écrivez prog1pour imprimer quelque chose en utilisant printf()et prog2pour lire quelque chose en utilisant scanf(). Alors viens de courir

./prog1 | ./prog2
Johan
la source
4

Voici un exemple :

int main()
{
    char buff[1024] = {0};
    FILE* cvt;
    int status;
    /* Launch converter and open a pipe through which the parent will write to it */
    cvt = popen("converter", "w");
    if (!cvt)
    {
        printf("couldn't open a pipe; quitting\n");
        exit(1)
    }
    printf("enter Fahrenheit degrees: " );
    fgets(buff, sizeof (buff), stdin); /*read user's input */
    /* Send expression to converter for evaluation */
    fprintf(cvt, "%s\n", buff);
    fflush(cvt);
    /* Close pipe to converter and wait for it to exit */
    status=pclose(cvt);
    /* Check the exit status of pclose() */
    if (!WIFEXITED(status))
        printf("error on closing the pipe\n");
    return 0;
}

Les étapes importantes de ce programme sont:

  1. L' popen()appel qui établit l'association entre un processus enfant et un tube dans le parent.
  2. L' fprintf()appel qui utilise le tube comme un fichier ordinaire pour écrire dans le stdin du processus enfant ou lire à partir de son stdout.
  3. L' pclose()appel qui ferme le canal et provoque la fin du processus enfant.
Preet Sangha
la source
Je pense que cet exemple manque le point de la question, bien que j'accorde que le programme "convertisseur" est un programme différent. Le premier commentaire traite de la communication entre des programmes complètement indépendants qui n'ont pas de relation frère / parent / cousin au second degré.
cmm
2

Tout d'abord, stdoutdemandez au programme 1 d'écrire la chaîne (comme si vous souhaitiez qu'elle apparaisse à l'écran). Ensuite, le deuxième programme doit lire une chaîne de stdin, comme si un utilisateur tapait à partir d'un clavier. puis vous exécutez:

$ program_1 | program_2
lfagundes
la source
1

Cette réponse pourrait être utile pour un futur Googleur.

#include <stdio.h>
#include <unistd.h>

int main(){     
     int p, f;  
     int rw_setup[2];   
     char message[20];      
     p = pipe(rw_setup);    
     if(p < 0){         
        printf("An error occured. Could not create the pipe.");  
        _exit(1);   
     }      
     f = fork();    
     if(f > 0){
        write(rw_setup[1], "Hi from Parent", 15);    
     }  
     else if(f == 0){       
        read(rw_setup[0],message,15);       
        printf("%s %d\n", message, r_return);   
     }  
     else{      
        printf("Could not create the child process");   
     }      
     return 0;

}

Vous pouvez trouver un exemple d'appel de canal bidirectionnel avancé ici .

Anjana
la source