PIPE FIFO API
V1.0
email: mesmerli@hotmail.com
前言
本文介紹 Linux 下,與 PIPE 與 FIFO 相關 API。
PIPE
PIPE 常用在輸出入的轉向。在 Linux 下使用 PIPE 有兩類 API:
- popen:較簡單
- pipe:適合進階應用
FIFO
FIFO 使用前,需要建立一個 FIFO node 在檔案系統中。可以使用以下命令建立:
- mknod MYFIFO p
- mkfifo a=rw MYFIFO
使用 popen 函數將外部程式的輸出,轉向到一個 file handler 供主程式處理
popen1.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
    FILE *read_fp;
    char buffer[BUFSIZ + 1];
    int chars_read;
    memset(buffer, '0', sizeof(buffer));
    read_fp = popen("uname -a", "r");
    if (read_fp != NULL) {
        chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
        if (chars_read > 0) {
            printf("Output was:-n%sn", buffer);
        }
        pclose(read_fp);
        exit(EXIT_SUCCESS);
    }
    exit(EXIT_FAILURE);
}
使用 popen 函數,讓外部程式的輸入,透過主程式供應
popen2.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
    FILE *write_fp;
    char buffer[BUFSIZ + 1];
    sprintf(buffer, "Once upon a time, there was...n");
    write_fp = popen("od -c", "w");
    if (write_fp != NULL) {
        fwrite(buffer, sizeof(char), strlen(buffer), write_fp);
        pclose(write_fp);
        exit(EXIT_SUCCESS);
    }
    exit(EXIT_FAILURE);
}
popen3.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
    FILE *read_fp;
    char buffer[BUFSIZ + 1];
    int chars_read;
    memset(buffer, '0', sizeof(buffer));
    read_fp = popen("ps -ax", "r");
    if (read_fp != NULL) {
        chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
        while (chars_read > 0) {
            buffer[chars_read - 1] = '0';
            printf("Reading:-n %sn", buffer);
            chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
        }
        pclose(read_fp);
        exit(EXIT_SUCCESS);
    }
    exit(EXIT_FAILURE);
}
popen4.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
    FILE *read_fp;
    char buffer[BUFSIZ + 1];
    int chars_read;
    memset(buffer, '0', sizeof(buffer));
    read_fp = popen("cat popen*.c | wc -l", "r");
    if (read_fp != NULL) {
        chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
        while (chars_read > 0) {
            buffer[chars_read - 1] = '0';
            printf("Reading:-n %sn", buffer);
            chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
        }
        pclose(read_fp);
        exit(EXIT_SUCCESS);
    }
    exit(EXIT_FAILURE);
}
使用 pipe 函數,註冊一組 pipe。 裡面有兩個 file handler。
當寫入 file handler 1,資料可以從 file handler 0 讀出
pipe1.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
    int data_processed;
    int file_pipes[2];
    const char some_data[] = "123";
    char buffer[BUFSIZ + 1];
memset(buffer, '0', sizeof(buffer));
    if (pipe(file_pipes) == 0) {
        data_processed = write(file_pipes[1], some_data, strlen(some_data));
        printf("Wrote %d bytesn", data_processed);
        data_processed = read(file_pipes[0], buffer, BUFSIZ);
        printf("Read %d bytes: %sn", data_processed, buffer);
        exit(EXIT_SUCCESS);
    }
    exit(EXIT_FAILURE);
}
建立兩個 process,並在兩個 process 之間透過 pipe 傳遞資料
pipe2.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
    int data_processed;
    int file_pipes[2];
    const char some_data[] = "123";
    char buffer[BUFSIZ + 1];
    pid_t fork_result;
memset(buffer, '0', sizeof(buffer));
    if (pipe(file_pipes) == 0) {
        fork_result = fork();
        if (fork_result == -1) {
            fprintf(stderr, "Fork failure");
            exit(EXIT_FAILURE);
        }
// We've made sure the fork worked, so if fork_result equals zero, we're in the child process.
        if (fork_result == 0) {
            data_processed = read(file_pipes[0], buffer, BUFSIZ);
            printf("Read %d bytes: %sn", data_processed, buffer);
            exit(EXIT_SUCCESS);
        }
// Otherwise, we must be the parent process.
        else {
            data_processed = write(file_pipes[1], some_data,
                                   strlen(some_data));
            printf("Wrote %d bytesn", data_processed);
        }
    }
    exit(EXIT_SUCCESS);
}
pipe3 與 pipe4 是一組共同實驗的程式,pipe3 執行外部程式 pipe4,並透過 pipe 傳遞資料給 pipe4
pipe3.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
    int data_processed;
    int file_pipes[2];
    const char some_data[] = "123";
    char buffer[BUFSIZ + 1];
    pid_t fork_result;
memset(buffer, '0', sizeof(buffer));
    if (pipe(file_pipes) == 0) {
        fork_result = fork();
        if (fork_result == (pid_t)-1) {
            fprintf(stderr, "Fork failure");
            exit(EXIT_FAILURE);
        }
        if (fork_result == 0) {
            sprintf(buffer, "%d", file_pipes[0]);
            (void)execl("pipe4", "pipe4", buffer, (char *)0);
            exit(EXIT_FAILURE);
        }
        else {
            data_processed = write(file_pipes[1], some_data,
                                   strlen(some_data));
            printf("%d - wrote %d bytesn", getpid(), data_processed);
        }
    }
    exit(EXIT_SUCCESS);
}
pipe4.c
// The 'consumer' program, pipe4.c, that reads the data is much simpler.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
    int data_processed;
    char buffer[BUFSIZ + 1];
    int file_descriptor;
    memset(buffer, '0', sizeof(buffer));
    sscanf(argv[1], "%d", &file_descriptor);
    data_processed = read(file_descriptor, buffer, BUFSIZ);
    printf("%d - read %d bytes: %sn", getpid(), data_processed, buffer);
    exit(EXIT_SUCCESS);
}
使用 pipe 轉向 stdin,讓主程式提供外部程式的輸入
pipe5.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
    int data_processed;
    int file_pipes[2];
    const char some_data[] = "123";
    pid_t fork_result;
    if (pipe(file_pipes) == 0) {
        fork_result = fork();
        if (fork_result == (pid_t)-1) {
            fprintf(stderr, "Fork failure");
            exit(EXIT_FAILURE);
        }
        if (fork_result == (pid_t)0) {
            close(0);
            dup(file_pipes[0]);
            close(file_pipes[0]);
            close(file_pipes[1]);
            execlp("od", "od", "-c", (char *)0);
            exit(EXIT_FAILURE);
        }
        else {
            close(file_pipes[0]);
            data_processed = write(file_pipes[1], some_data,
                                   strlen(some_data));
            close(file_pipes[1]);
            printf("%d - wrote %d bytesn", (int)getpid(), data_processed);
        }
    }
    exit(EXIT_SUCCESS);
}
利用 mkfifo 在檔案系統上建立 fifo 節點
fifo1.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
int main()
{
    int res = mkfifo("/tmp/my_fifo", 0777);
    if (res == 0)
        printf("FIFO createdn");
    exit(EXIT_SUCCESS);
}
使用不同的模式開啟檔案系統上的 fifo 檔案
fifo2.c
// Let's start with the header files, a #define and the check that the correct number
// of command-line arguments have been supplied.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FIFO_NAME "/tmp/my_fifo"
int main(int argc, char *argv[])
{
    int res;
    int open_mode = 0;
    int i;
    if (argc < 2) {
        fprintf(stderr, "Usage: %s <some combination of
               O_RDONLY O_WRONLY O_NONBLOCK>n", *argv);
        exit(EXIT_FAILURE);
    }
// Assuming that the program passed the test, we now set the value of open_mode
// from those arguments.
    for(i = 1; i < argc; i++) {
        if (strncmp(*++argv, "O_RDONLY", 8) == 0)
             open_mode |= O_RDONLY;
        if (strncmp(*argv, "O_WRONLY", 8) == 0)
             open_mode |= O_WRONLY;
        if (strncmp(*argv, "O_NONBLOCK", 10) == 0)
             open_mode |= O_NONBLOCK;
     }
// We now check whether the FIFO exists and create it if necessary.
// Then the FIFO is opened and output given to that effect while the program
// catches forty winks. Last of all, the FIFO is closed.
    if (access(FIFO_NAME, F_OK) == -1) {
        res = mkfifo(FIFO_NAME, 0777);
        if (res != 0) {
            fprintf(stderr, "Could not create fifo %sn", FIFO_NAME);
            exit(EXIT_FAILURE);
        }
    }
    printf("Process %d opening FIFOn", getpid());
    res = open(FIFO_NAME, open_mode);
    printf("Process %d result %dn", getpid(), res);
    sleep(5);
    if (res != -1) (void)close(res);
    printf("Process %d finishedn", getpid());
    exit(EXIT_SUCCESS);
}
fifo3 與 fifo4 為一組共同實驗的程式,fifo3 傳遞資料給 fifo4
fifo3.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#define PIPE_BUF 4096
#define FIFO_NAME "/tmp/my_fifo"
#define BUFFER_SIZE PIPE_BUF
#define TEN_MEG (1024 * 1024 * 10)
int main()
{
    int pipe_fd;
    int res;
    int open_mode = O_WRONLY;
    int bytes_sent = 0;
    char buffer[BUFFER_SIZE + 1];
    if (access(FIFO_NAME, F_OK) == -1) {
        res = mkfifo(FIFO_NAME, 0777);
        if (res != 0) {
            fprintf(stderr, "Could not create fifo %sn", FIFO_NAME);
            exit(EXIT_FAILURE);
        }
    }
    printf("Process %d opening FIFO O_WRONLYn", getpid());
    pipe_fd = open(FIFO_NAME, open_mode);
    printf("Process %d result %dn", getpid(), pipe_fd);
    if (pipe_fd != -1) {
        while(bytes_sent < TEN_MEG) {
            res = write(pipe_fd, buffer, BUFFER_SIZE);
            if (res == -1) {
                fprintf(stderr, "Write error on pipen");
                exit(EXIT_FAILURE);
            }
            bytes_sent += res;
        }
        (void)close(pipe_fd); 
    }
    else {
        exit(EXIT_FAILURE);        
    }
    printf("Process %d finishedn", getpid());
    exit(EXIT_SUCCESS);
}
fifo4.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#define PIPE_BUF 4096
#define FIFO_NAME "/tmp/my_fifo"
#define BUFFER_SIZE PIPE_BUF
int main()
{
    int pipe_fd;
    int res;
    int open_mode = O_RDONLY;
    char buffer[BUFFER_SIZE + 1];
    int bytes_read = 0;
    memset(buffer, '0', sizeof(buffer));
    
    printf("Process %d opening FIFO O_RDONLYn", getpid());
    pipe_fd = open(FIFO_NAME, open_mode);
    printf("Process %d result %dn", getpid(), pipe_fd);
    if (pipe_fd != -1) {
        do {
            res = read(pipe_fd, buffer, BUFFER_SIZE);
            bytes_read += res;
        } while (res > 0);
        (void)close(pipe_fd);
    }
    else {
        exit(EXIT_FAILURE);
    }
    printf("Process %d finished, %d bytes readn", getpid(), bytes_read);
    exit(EXIT_SUCCESS);
}
Makefile
CROSS_COMPILE = arm-linux-
LINUXDIR = /usr/src/creator/s3c2410/linux
export LINUXDIR
#
# Include the make variables (CC, etc...)
#
AS  = $(CROSS_COMPILE)as
LD  = $(CROSS_COMPILE)ld
CC  = $(CROSS_COMPILE)gcc
CPP  = $(CC) -E
AR  = $(CROSS_COMPILE)ar
export AS LD CC CPP AR
CFLAGS= -O0 -gdwarf-2 -DHAVE_CONFIG_H -DFPM_DEFAULT -Dlinux -Dunix -DNDEBUG -D_REENTRANT -I.
.c.o:
 $(CC) $(CFLAGS) -c -o $@ $<
.S.o:
 $(CC) $(AFLAGS) -c -o $@ $<
all: fifo1 fifo2 fifo3 fifo4 pipe1 pipe2 pipe3 pipe4 pipe5 popen1 popen2 popen3 popen4
fifo1: fifo1.o
 $(CC) $(LDFLAGS) -o $@ $^  $(LDLIBS)  -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
fifo2: fifo2.o
 $(CC) $(LDFLAGS) -o $@ $^  $(LDLIBS)  -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
fifo3: fifo3.o
 $(CC) $(LDFLAGS) -o $@ $^  $(LDLIBS)  -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
fifo4: fifo4.o
 $(CC) $(LDFLAGS) -o $@ $^  $(LDLIBS)  -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
pipe1: pipe1.o
 $(CC) $(LDFLAGS) -o $@ $^  $(LDLIBS)  -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
pipe2: pipe2.o
 $(CC) $(LDFLAGS) -o $@ $^  $(LDLIBS)  -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
pipe3: pipe3.o
 $(CC) $(LDFLAGS) -o $@ $^  $(LDLIBS)  -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
pipe4: pipe4.o
 $(CC) $(LDFLAGS) -o $@ $^  $(LDLIBS)  -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
pipe5: pipe5.o
 $(CC) $(LDFLAGS) -o $@ $^  $(LDLIBS)  -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
popen1: popen1.o
 $(CC) $(LDFLAGS) -o $@ $^  $(LDLIBS)  -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
popen2: popen2.o
 $(CC) $(LDFLAGS) -o $@ $^  $(LDLIBS)  -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
popen3: popen3.o
 $(CC) $(LDFLAGS) -o $@ $^  $(LDLIBS)  -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
popen4: popen4.o
 $(CC) $(LDFLAGS) -o $@ $^  $(LDLIBS)  -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
#client.o: client.h
#server.o: client.h
clean:
 rm -f fifo1 fifo2 fifo3 fifo4 pipe1 pipe2 pipe3 pipe4 pipe5 popen1 popen2 popen3 popen4 client server /tmp/my_fifo *.o
 



0 意見:
張貼留言