¿Cómo enviar una cadena simple entre dos programas usando tuberías?

111

Intenté buscar en la red, pero apenas hay recursos. Bastaría un pequeño ejemplo.

EDITAR Quiero decir, dos programas C diferentes que se comunican entre sí. Un programa debería enviar "Hola" y el otro debería recibirlo. Algo como eso.


fuente
1
¿Presumiblemente no te refieres a algo como ls | grep ".o"? Quizás una explicación un poco más de lo que quiere decir ayudaría ...
Jerry Coffin
13
Vamos hombre ... un poco de esfuerzo. Google "código de ejemplo de tuberías c". El primer resultado es exacto: tldp.org/LDP/lpg/node11.html
Stephen
4
Quiero comunicación entre dos programas completamente diferentes. No pude encontrar un recurso para eso.
1
Si no está bifurcando un proceso, debe buscar en "tuberías con nombre".
Juez Maygarden

Respuestas:

156

Una tubería normal solo puede conectar dos procesos relacionados. Es creado por un proceso y desaparecerá cuando el último proceso lo cierre.

Una tubería con nombre , también llamada FIFO por su comportamiento, se puede utilizar para conectar dos procesos no relacionados y existe independientemente de los procesos; lo que significa que puede existir incluso si nadie lo está usando. Se crea un FIFO utilizando la mkfifo()función de biblioteca.

Ejemplo

escritor.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: La comprobación de errores se omitió en el código anterior para simplificar.

jschmier
fuente
6
¿Qué se considera procesos relacionados ?
Pithikos
7
Probablemente procesos que están relacionados a través de una o más relaciones padre / hijo (por ejemplo, incluye hermanos). El ancestro común habría creado los dos extremos de la tubería. Los procesos no relacionados carecen de ese ancestro común.
MSalters
4
Esto no funcionará si el lector comienza primero. Una solución rápida sería poner el open()del lector dentro de un bucle. Sin embargo +1 porque proporciona un ejemplo de dos programas.
gsamaras
Supongo que este ejemplo necesita algunos ajustes para funcionar en Windows. unistd.h siendo POSIX y todo ...
David Karlsson
Sí, necesitará ajustes para Windows. El artículo de Wikipedia sobre canalizaciones con nombre analiza algunas de las diferencias Unix / Windows y una búsqueda rápida en Google puede ayudar con la implementación de Windows.
jschmier
41

Desde Crear tuberías en C , esto le muestra cómo bifurcar un programa para usar una tubería. Si no quiere fork (), puede usar canalizaciones con nombre .

Además, puede obtener el efecto de prog1 | prog2enviar la salida de prog1a stdout y leer desde stdinin prog2. También puede leer stdin abriendo un archivo llamado /dev/stdin(pero no estoy seguro de la portabilidad de eso).

/*****************************************************************************
 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
fuente
1
Hola Stephen, de todos modos, ¿puedo usar este código para dos funciones diferentes? lo que significa que la escritura en la tubería se realiza en una función y la lectura de la tubería en otra función. Se agradecería un código de trabajo como este.
Mohsin
8
dup2( STDIN_FILENO, newfd )

Y leer:

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

Pero creo que fcntlpuede ser una mejor solución

echo "salut" | code
mlouk
fuente
6

Lo que un programa escribe en stdout puede ser leído por otro a través de stdin. Así que simplemente, usando c, escriba prog1para imprimir algo usando printf()y prog2para leer algo usando scanf(). Entonces solo corre

./prog1 | ./prog2
Johan
fuente
4

He aquí una muestra :

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

Los pasos importantes de este programa son:

  1. La popen()llamada que establece la asociación entre un proceso hijo y una tubería en el padre.
  2. los fprintf() llamada que usa la tubería como un archivo ordinario para escribir en el stdin del proceso hijo o leer desde su stdout.
  3. La pclose()llamada que cierra la tubería y hace que termine el proceso hijo.
Preet Sangha
fuente
Creo que este ejemplo pierde el sentido de la pregunta, aunque reconozco que el programa "convertidor" es un programa diferente. El primer comentario aborda la comunicación entre programas completamente independientes que no tienen una relación de hermano / padre / primo segundo.
cmm
2

Primero, stdouthaga que el programa 1 escriba la cadena (como si quisiera que apareciera en la pantalla). Luego, el segundo programa debería leer una cadena de stdin, como si un usuario estuviera escribiendo desde un teclado. luego corres:

$ program_1 | program_2
lfagundes
fuente
1

Esta respuesta podría ser útil para 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;

}

Puede encontrar un ejemplo avanzado de llamada de canalización bidireccional aquí .

Anjana
fuente