Boruları kullanarak iki program arasında basit bir dizi nasıl gönderilir?


111

İnternette aramayı denedim, ancak neredeyse hiç kaynak yok. Küçük bir örnek yeterli olacaktır.

DÜZENLE Demek istediğim, birbiriyle iletişim kuran iki farklı C programı. Bir program "Merhaba" göndermeli ve diğeri onu almalıdır. Bunun gibi bir şey.

c  unix  pipe 

1
Muhtemelen böyle bir şey demek istemiyorsunuz ls | grep ".o"? Belki de ne demek istediğine dair biraz daha açıklama yardımcı olabilir ...
Jerry Coffin

13
Hadi dostum ... biraz çaba. Google "c boruları örnek kodu". İlk sonuç kesin: tldp.org/LDP/lpg/node11.html
Stephen

4
Tamamen farklı iki program arasında iletişim istiyorum. Bunun için bir kaynak bulamadım.

1
Bir süreci çatallamıyorsanız, "adlandırılmış borular" a bakmanız gerekir.
Yargıç Maygarden

Yanıtlar:


156

Normal bir boru yalnızca iki ilgili işlemi birbirine bağlayabilir. Bir süreç tarafından yaratılır ve son süreç onu kapattığında kaybolur.

Bir adlandırılmış kanal , aynı zamanda, davranışı için bir FIFO olarak adlandırılan iki işlem bağlamak için kullanılan ve bağımsız bir şekilde, işlemlerin mevcut olabilir; Yani kimse kullanmasa bile var olabilir. mkfifo()Kitaplık işlevi kullanılarak bir FIFO oluşturulur .

Misal

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

Not: Hata kontrolü, basitlik açısından yukarıdaki koddan çıkarılmıştır.


6
Ne sayılır ilgili süreçleri ?
Pithikos

7
Muhtemelen bir veya daha fazla ebeveyn / çocuk ilişkisi yoluyla ilişkili süreçler (örneğin kardeşleri içerir). Ortak ata, borunun iki ucunu yaratırdı. İlişkisiz süreçler bu ortak atadan yoksundur.
MSalters

4
Okuyucu önce başlarsa bu işe yaramayacaktır. Hızlı bir çözüm open(), okuyucuyu bir döngü içine koymak olacaktır . Ancak +1, çünkü iki program örneği sağlıyorsunuz.
gsamaras

Sanırım bu örnekte pencerelerde çalışmak için biraz ince ayar gerekiyor mu? unistd.h, POSIX ve hepsi ...
David Karlsson

Evet, Windows için ince ayar yapılması gerekecek. Adlandırılmış boruların Wikipedia makalesi Unix / Windows farklılıkları ve hızlı bazılarını ele Google arama , Windows uygulaması ile kutu yardımı.
jschmier

41

Gönderen C Borular oluşturma , bu gösterileri nasıl bir boru kullanmak için bir program çatal. Fork () istemiyorsanız, adlandırılmış kanalları kullanabilirsiniz .

Ayrıca, etkisini elde edebilirsiniz prog1 | prog2çıktısını göndererek prog1Stdout'a ve okuma stdiniçinde prog2. Adlı bir dosyayı açarak da stdin'i okuyabilirsiniz /dev/stdin(ancak bunun taşınabilirliğinden emin olamazsınız).

/*****************************************************************************
 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
Hey Stephen, bu kodu iki farklı işlev için kullanabilir miyim? anlamı boruya yazmak bir işlevde ve boruyu başka bir işlevde okumak mı? bunun gibi bir çalışma kodu takdir edilecektir.
Mohsin

8
dup2( STDIN_FILENO, newfd )

Ve OKU:

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

Ama bunun fcntldaha iyi bir çözüm olabileceğini düşünüyorum

echo "salut" | code

6

Bir programın stdout'a yazdığı şey bir başkası tarafından stdin aracılığıyla okunabilir. Yani basitçe, c kullanarak, kullanarak bir prog1şeyler yazdırmak printf()ve prog2kullanarak bir şeyler okumak için yazın scanf(). O zaman sadece koş

./prog1 | ./prog2

4

İşte bir örnek :

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

Bu programdaki önemli adımlar:

  1. Üst popen()süreç ile alt süreç arasındaki ilişkiyi kuran çağrı.
  2. fprintf()Çocuk sürecin stdin'e yazma sıradan bir dosya olarak boruyu kullanan veya çağrı onun Stdout'a okunan.
  3. pclose()Borusunu kapatan ve Çocuk sürecin sonlanmasına neden olur diyoruz.

"Dönüştürücü" programının farklı bir program olduğunu kabul etsem de, bu örnek sorunun özünü kaçırdığını düşünüyorum. İlk yorum, kardeş / ebeveyn / ikinci kuzen ilişkisi olmayan tamamen bağımsız programlar arasındaki iletişimi ele alır.
cmm

2

İlk olarak, program 1'in dizeyi yazmasını sağlayın stdout(sanki ekranda görünmesini istiyorsanız). Sonra ikinci program stdin, sanki bir kullanıcı klavyeden yazıyormuş gibi bir dizeyi okumalıdır . sonra koşarsın:

$ program_1 | program_2

1

Bu yanıt, gelecekteki bir Google çalışanı için yararlı olabilir.

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

}

Burada gelişmiş bir iki yönlü boru çağrısı örneği bulabilirsiniz .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.