星期六, 5月 12, 2007

PIPE FIFO API

V1.0

copyright@2006

email: mesmerli@hotmail.com

前言

本文介紹 Linux 下,與 PIPE 與 FIFO 相關 API。

PIPE

PIPE 常用在輸出入的轉向。在 Linux 下使用 PIPE 有兩類 API:

  1. popen:較簡單
  2. pipe:適合進階應用

FIFO

FIFO 使用前,需要建立一個 FIFO node 在檔案系統中。可以使用以下命令建立:

  1. mknod MYFIFO p
  2. 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 意見: