Come inviare una semplice stringa tra due programmi utilizzando pipe?


111

Ho provato a cercare in rete, ma non ci sono quasi risorse. Basterebbe un piccolo esempio.

EDIT Voglio dire, due diversi programmi C che comunicano tra loro. Un programma dovrebbe inviare "Ciao" e l'altro dovrebbe riceverlo. Qualcosa del genere.

c  unix  pipe 

1
Presumibilmente non intendi qualcosa come ls | grep ".o"? Forse una spiegazione un po 'più di quello che intendi potrebbe aiutare ...
Jerry Coffin

13
Andiamo amico ... un piccolo sforzo. Google "codice di esempio c pipe". Il primo risultato è esatto: tldp.org/LDP/lpg/node11.html
Stephen

4
Voglio la comunicazione tra due programmi completamente diversi. Non sono riuscito a trovare una risorsa per questo.

1
Se non stai biforcando un processo, devi guardare "pipe con nome".
Giudice Maygarden

Risposte:


156

Un tubo normale può collegare solo due processi correlati. Viene creato da un processo e svanirà quando l'ultimo processo lo chiuderà.

Una named pipe , chiamata anche FIFO per il suo comportamento, può essere utilizzata per connettere due processi non correlati ed esiste indipendentemente dai processi; il che significa che può esistere anche se nessuno lo sta usando. Un FIFO viene creato utilizzando la mkfifo()funzione di libreria.

Esempio

writer.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;
}

reader.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;
}

Nota: il controllo degli errori è stato omesso dal codice precedente per semplicità.


6
Cosa sono considerati processi correlati ?
Pithikos

7
Probabilmente processi che sono correlati tramite una o più relazioni genitore / figlio (ad esempio, include i fratelli). L'antenato comune avrebbe creato le due estremità del tubo. I processi non correlati mancano di quell'antenato comune.
MSalters il

4
Questo non funzionerà se il lettore inizia per primo. Una soluzione rapida potrebbe essere quella di mettere il open()del lettore all'interno di un ciclo. Tuttavia +1 perché fornisci un esempio di due programmi.
gsamaras

Presumo che questo esempio abbia bisogno di qualche ritocco per funzionare su Windows? unistd.h è POSIX e tutto ...
David Karlsson

Sì, sarà necessario modificare per Windows. L' articolo di Wikipedia sulle pipe denominate discute alcune delle differenze tra Unix e Windows e una rapida ricerca su Google può aiutare con l'implementazione di Windows.
jschmier

41

Da Creazione di pipe in C , questo mostra come eseguire il fork di un programma per utilizzare un pipe. Se non vuoi fork (), puoi usare named pipe .

Inoltre, puoi ottenere l'effetto di prog1 | prog2inviando l'output di prog1a stdout e leggendo da stdinin prog2. Puoi anche leggere stdin aprendo un file denominato /dev/stdin(ma non sei sicuro della sua portabilità).

/*****************************************************************************
 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);
}

1
Ehi Stephen, comunque posso usare questo codice per due diverse funzioni? significa che la scrittura nella pipe viene eseguita in una funzione e la lettura della pipe in un'altra funzione ?? un codice funzionante come questo sarebbe apprezzato.
Mohsin

8
dup2( STDIN_FILENO, newfd )

E leggi:

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 );    

Ma penso che fcntlpossa essere una soluzione migliore

echo "salut" | code

6

Ciò che un programma scrive su stdout può essere letto da un altro tramite stdin. Quindi, semplicemente, usando c, scrivi prog1per stampare qualcosa usando printf()e prog2per leggere qualcosa usando scanf(). Allora corri e basta

./prog1 | ./prog2

4

Ecco un esempio :

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;
}

I passaggi importanti in questo programma sono:

  1. La popen()chiamata che stabilisce l'associazione tra un processo figlio e una pipe nel genitore.
  2. Il fprintf() chiamata che usa la pipe come un normale file per scrivere nello stdin del processo figlio o leggere dal suo stdout.
  3. La pclose()chiamata che chiude la pipe e causa il termine del processo figlio.

Penso che questo esempio non coglie il punto della domanda, anche se ammetto che il programma "convertitore" è un programma diverso. Il primo commento riguarda la comunicazione tra programmi completamente indipendenti che non hanno una relazione fratello / genitore / secondo cugino.
cmm

2

Innanzitutto, chiedi al programma 1 di scrivere la stringa stdout(come se desideri che appaia sullo schermo). Quindi il secondo programma dovrebbe leggere una stringa da stdin, come se un utente stesse digitando da una tastiera. poi corri:

$ program_1 | program_2

1

Questa risposta potrebbe essere utile per un futuro googler.

#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;

}

Puoi trovare un esempio avanzato di chiamata pipe a due vie qui .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.