Wie sende ich eine einfache Zeichenfolge zwischen zwei Programmen mithilfe von Pipes?

111

Ich habe versucht, im Internet zu suchen, aber es gibt kaum Ressourcen. Ein kleines Beispiel würde ausreichen.

EDIT Ich meine, zwei verschiedene C-Programme, die miteinander kommunizieren. Ein Programm sollte "Hi" senden und das andere sollte es empfangen. Sowas in der Art.


quelle
1
Vermutlich meinst du nicht so etwas ls | grep ".o"? Vielleicht hilft ein bisschen mehr Erklärung, was Sie meinen ...
Jerry Coffin
13
Komm schon Mann ... eine kleine Anstrengung. Google "c pipes Beispielcode". Das erste Ergebnis ist genau: tldp.org/LDP/lpg/node11.html
Stephen
4
Ich möchte die Kommunikation zwischen zwei völlig unterschiedlichen Programmen. Ich konnte keine Ressource dafür finden.
1
Wenn Sie keinen Prozess forken, müssen Sie sich "Named Pipes" ansehen.
Richter Maygarden

Antworten:

156

Eine reguläre Pipe kann nur zwei verwandte Prozesse verbinden. Es wird von einem Prozess erstellt und verschwindet, wenn der letzte Prozess es schließt.

Eine Named Pipe , die aufgrund ihres Verhaltens auch als FIFO bezeichnet wird, kann zum Verbinden zweier nicht zusammenhängender Prozesse verwendet werden und existiert unabhängig von den Prozessen. Das heißt, es kann existieren, selbst wenn niemand es benutzt. Mit der mkfifo()Bibliotheksfunktion wird ein FIFO erstellt .

Beispiel

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

Hinweis: Die Fehlerprüfung wurde der Einfachheit halber im obigen Code weggelassen.

jschmier
quelle
6
Was sind verwandte Prozesse ?
Pithikos
7
Wahrscheinlich Prozesse, die über eine oder mehrere Eltern-Kind-Beziehungen miteinander verbunden sind (z. B. Geschwister). Der gemeinsame Vorfahr hätte die beiden Enden der Pfeife geschaffen. In nicht verwandten Prozessen fehlt dieser gemeinsame Vorfahr.
MSalters
4
Dies funktioniert nicht, wenn der Leser zuerst startet. Eine schnelle Lösung wäre, open()den Leser in eine Schleife zu stecken. Jedoch +1, da Sie ein Beispiel für zwei Programme angeben.
Gsamaras
Ich nehme an, dieses Beispiel muss angepasst werden, um unter Windows zu arbeiten. unistd.h ist POSIX und alle ...
David Karlsson
Ja, es muss für Windows optimiert werden. Der Wikipedia-Artikel zu Named Pipes beschreibt einige der Unix / Windows-Unterschiede. Eine schnelle Google-Suche kann bei der Windows-Implementierung hilfreich sein.
Jschmier
41

In Erstellen von Pipes in C erfahren Sie, wie Sie ein Programm zur Verwendung einer Pipe verzweigen. Wenn Sie fork () nicht möchten, können Sie Named Pipes verwenden .

Darüber hinaus können Sie den Effekt erzielen, prog1 | prog2indem Sie die Ausgabe von prog1an stdout senden und von stdinin lesen prog2. Sie können stdin auch lesen, indem Sie eine Datei mit dem Namen öffnen /dev/stdin(aber nicht sicher sind, ob diese portierbar ist).

/*****************************************************************************
 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
quelle
1
Hey Stephen, kann ich diesen Code trotzdem für zwei verschiedene Funktionen verwenden? Bedeutet das Schreiben in die Pipe in einer Funktion und das Lesen der Pipe in einer anderen Funktion? Ein solcher Arbeitscode wäre willkommen.
Mohsin
8
dup2( STDIN_FILENO, newfd )

Und lese:

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

Aber ich denke, das fcntlkann eine bessere Lösung sein

echo "salut" | code
mlouk
quelle
6

Was ein Programm in stdout schreibt, kann von einem anderen über stdin gelesen werden. So einfach, mit c, schreiben Sie prog1etwas drucken verwenden printf()und prog2etwas mit lesen scanf(). Dann renn einfach

./prog1 | ./prog2
Johan
quelle
4

Hier ist ein Beispiel :

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

Die wichtigen Schritte in diesem Programm sind:

  1. Der popen()Aufruf, der die Zuordnung zwischen einem untergeordneten Prozess und einer Pipe im übergeordneten Prozess herstellt.
  2. Der fprintf()Aufruf, der die Pipe als normale Datei verwendet, um in das stdin des untergeordneten Prozesses zu schreiben oder aus dessen stdout zu lesen.
  3. Der pclose()Aufruf, der die Pipe schließt und den untergeordneten Prozess beendet.
Preet Sangha
quelle
Ich denke, dieses Beispiel verfehlt den Punkt der Frage, obwohl ich zugebe, dass das "Konverter" -Programm ein anderes Programm ist. Der erste Kommentar befasst sich mit der Kommunikation zwischen völlig unabhängigen Programmen, die keine Beziehung zwischen Geschwister, Eltern und zweitem Cousin haben.
cmm
2

Lassen Sie zuerst Programm 1 die Zeichenfolge schreiben stdout(als ob sie auf dem Bildschirm angezeigt werden soll). Dann sollte das zweite Programm eine Zeichenfolge lesen stdin, als würde ein Benutzer über eine Tastatur tippen. dann rennst du:

$ program_1 | program_2
lfagundes
quelle
1

Diese Antwort könnte für einen zukünftigen Googler hilfreich sein.

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

}

Ein Beispiel für einen erweiterten Zwei-Wege-Pipe-Aufruf finden Sie hier .

Anjana
quelle