Làm thế nào để gửi một chuỗi đơn giản giữa hai chương trình bằng cách sử dụng đường ống?


111

Tôi đã thử tìm kiếm trên mạng, nhưng hầu như không có bất kỳ tài nguyên nào. Một ví dụ nhỏ là đủ.

EDIT Ý tôi là, hai chương trình C khác nhau giao tiếp với nhau. Một chương trình sẽ gửi "Hi" và chương trình kia sẽ nhận được. Đại loại vậy.

c  unix  pipe 

1
Có lẽ bạn không có nghĩa là một cái gì đó như thế ls | grep ".o"nào? Có lẽ giải thích thêm một chút về ý bạn sẽ giúp ích ...
Jerry Coffin

13
Cố lên anh bạn ... cố gắng một chút. Google "mã ví dụ c pipe". Kết quả đầu tiên là chính xác: tldp.org/LDP/lpg/node11.html
Stephen

4
Tôi muốn giao tiếp giữa hai chương trình hoàn toàn khác nhau. Tôi đã không thể tìm thấy một tài nguyên cho điều đó.

1
Nếu bạn không đặt một quy trình, thì bạn cần phải xem "các đường ống được đặt tên".
Judge Maygarden

Câu trả lời:


156

Một đường ống thông thường chỉ có thể kết nối hai quy trình liên quan. Nó được tạo ra bởi một quá trình và sẽ biến mất khi quá trình cuối cùng đóng nó.

Một đường ống được đặt tên , còn được gọi là FIFO cho hành vi của nó, có thể được sử dụng để kết nối hai quy trình không liên quan và tồn tại độc lập với các quy trình; nghĩa là nó có thể tồn tại ngay cả khi không có ai sử dụng nó. FIFO được tạo bằng cách sử dụng mkfifo()chức năng thư viện.

Thí dụ

nhà văn.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;
}

Lưu ý: Kiểm tra lỗi đã được bỏ qua trong đoạn mã trên để đơn giản hóa.


6
Những gì được coi là các quá trình liên quan ?
Pithikos

7
Có thể là các quy trình có liên quan thông qua một hoặc nhiều quan hệ cha / con (ví dụ: bao gồm anh chị em ruột). Tổ tiên chung sẽ tạo ra hai đầu của đường ống. Các quy trình không liên quan thiếu tổ tiên chung đó.
MSalters

4
Điều này sẽ không hiệu quả nếu người đọc khởi động trước. Một cách khắc phục nhanh chóng là đặt open()đầu đọc vào trong một vòng lặp. Tuy nhiên +1 vì bạn cung cấp một ví dụ hai chương trình.
gsamaras

Tôi lấy ví dụ này cần một số tinh chỉnh để hoạt động trên windows? unistd.h là POSIX và tất cả các ...
David Karlsson

Có, nó sẽ cần điều chỉnh cho Windows. Các bài viết trên Wikipedia về ống tên thảo luận về một số khác biệt Unix / Windows và một cách nhanh chóng của Google tìm kiếm có thể giúp với việc thực hiện Windows.
jschmier

41

Từ Tạo Pipes trong C , phần này cho bạn thấy cách phân nhánh một chương trình để sử dụng pipe. Nếu bạn không muốn fork (), bạn có thể sử dụng các đường ống có tên .

Ngoài ra, bạn có thể nhận được hiệu ứng của prog1 | prog2bằng cách gửi đầu ra prog1tới stdout và đọc từ bên stdintrong prog2. Bạn cũng có thể đọc stdin bằng cách mở một tệp có tên /dev/stdin(nhưng không chắc chắn về tính di động của tệp đó).

/*****************************************************************************
 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
Này Stephen, dù sao thì tôi có thể sử dụng mã này cho hai chức năng khác nhau? nghĩa là ghi vào đường ống được thực hiện trong một chức năng và đọc đường ống trong một chức năng khác ?? một mã làm việc như thế này sẽ được đánh giá cao.
Mohsin

8
dup2( STDIN_FILENO, newfd )

Và đọc:

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

Nhưng, tôi nghĩ đó fcntlcó thể là một giải pháp tốt hơn

echo "salut" | code

6

Những gì một chương trình ghi vào stdout có thể được đọc bởi chương trình khác thông qua stdin. Vì vậy, đơn giản, sử dụng c, viết prog1để in một cái gì đó bằng cách sử dụng printf()prog2để đọc cái gì đó bằng cách sử dụng scanf(). Sau đó chỉ cần chạy

./prog1 | ./prog2

4

Đây là một mẫu :

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

Các bước quan trọng trong chương trình này là:

  1. Các popen() gọi thiết lập mối liên kết giữa một tiến trình con và một đường ống trong cha mẹ.
  2. Các fprintf() gọi sử dụng đường dẫn như một tệp thông thường để ghi vào stdin của tiến trình con hoặc đọc từ stdout của nó.
  3. Lệnh pclose()gọi đóng đường ống và khiến tiến trình con kết thúc.

Tôi nghĩ rằng ví dụ này bỏ sót điểm của câu hỏi, mặc dù tôi cho rằng chương trình "chuyển đổi" là một chương trình khác. Nhận xét đầu tiên đề cập đến giao tiếp giữa các chương trình hoàn toàn độc lập không có mối quan hệ anh chị em / cha mẹ / anh chị em họ.
cmm,

2

Đầu tiên, yêu cầu chương trình 1 ghi chuỗi vào stdout(như thể bạn muốn nó xuất hiện trên màn hình). Sau đó, chương trình thứ hai sẽ đọc một chuỗi từ stdin, như thể người dùng đang gõ từ bàn phím. sau đó bạn chạy:

$ program_1 | program_2

1

Câu trả lời này có thể hữu ích cho một nhân viên Google trong tương lai.

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

}

Bạn có thể tìm thấy ví dụ về cuộc gọi đường ống hai chiều nâng cao tại đây .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.