Assoc. Prof. Wiroon Sriborrirux, Founder of Advance Innovation Center (AIC) and Bangsaen Design House (BDH), Electrical Engineering Department, Faculty of Engineering, Burapha University
แสดงตัวอย่างการใช้ popen() เพื่อรับข้อมูลที่อ่านได้จากคำสั่ง ls แล้วส่งต่อไปเป็นอินพุทให้กับอีกคำสั่ง (sort) เพื่อทำการจัดเรียงข้อมูลต่อไป
#include<stdio.h>#include<stdlib.h>intmain(void) { FILE *pipein_fp,*pipeout_fp;char readbuf[80]; /* Create one way pipe line with call to popen() */if ((pipein_fp =popen("ls /","r")) ==NULL) {perror("popen");exit(1); } /* Create one way pipe line with call to popen() */if ((pipeout_fp =popen("sort","w")) ==NULL) {perror("popen");exit(1); } /* Processing loop */while (fgets(readbuf,80, pipein_fp))fputs(readbuf, pipeout_fp); /* Close the pipes */pclose(pipein_fp);pclose(pipeout_fp);return (0);}
$ ls /
NAS courseweb_backup etc initrd.img.old lib64 mnt root selinux tftpboot var bin dev home lib lost+found opt run srv tmp vmlinuz boot ee_backup initrd.img lib32 media proc sbin sys usr vmlinuz.old
$ gcc -o pipe3 pipe3.c -Wall
$ ./pipe3
NAS
bin
boot
courseweb_backup
dev
ee_backup
etc
home
initrd.img
initrd.img.old
lib
lib32
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
selinux
srv
sys
tftpboot
tmp
usr
var
vmlinuz
vmlinuz.old
ตัวอย่างที่ 4
แสดงตัวอย่างการรับอาร์กิวเมนต์จากผู้ใช้ผ่านการเรียกโปรแกรมจาก command line โดยอาร์กิวเมนต์ตัวแรกจะเป็นคำสั่งที่ต้องการให้รับข้อมูล (write) และอาร์กิวเมนต์ที่สองจะเป็นไฟล์ข้อมูลที่ต้องการจะให้เปิดอ่าน (rt)
/***************************************************************************** Excerpt from "Linux Programmer's Guide - Chapter 6" (C)opyright 1994-1995, Scott Burkett ***************************************************************************** Filename: popen.c *****************************************************************************/#include<stdio.h>#include<stdlib.h>intmain(int argc,char*argv[]) { FILE *pipe_fp,*infile;char readbuf[80];if (argc !=3) {fprintf(stderr,"USAGE: popen3 [command] [filename]\n");exit(1); } /* Open up input file */if ((infile =fopen(argv[2],"rt")) ==NULL) {perror("fopen");exit(1); } /* Create one way pipe line with call to popen() */if ((pipe_fp =popen(argv[1],"w")) ==NULL) {perror("popen");exit(1); } /* Processing loop */do {fgets(readbuf,80, infile);if (feof(infile))break;fputs(readbuf, pipe_fp); } while (!feof(infile));fclose(infile);pclose(pipe_fp);return (0);}
แสดงตัวอย่างการประยุกต์การส่งข้อความ (message) ระหว่างโปรเซสต่างๆ โดยโปรเซสที่ i ต้องการส่งไปยังโปรเซสที่ j โดยถ้าโปรเซสใดรับข้อความเพียงสองครั้งแล้วก็จะสิ้นสุดการทำงาน
/* * pipe4.c * * A set of processes randomly messaging each the other, with pipes. * * * Created by Mij <mij@bitchx.it> on 05/01/05. * Original source file available on http://mij.oltrelinux.com/devel/unixprg/ * */#include<stdio.h>/* for read() and write() */#include<sys/types.h>#include<sys/uio.h>/* for strlen and others */#include<string.h>/* for pipe() */#include<unistd.h>/* for [s]random() */#include<stdlib.h>/* for time() [seeding srandom()] */#include<time.h>/* for signals */#include<signal.h>#definePROCS_NUM15 /* 1 < number of processes involved <= 255 */#defineMAX_PAYLOAD_LENGTH50 /* message length */#defineDEAD_PROC-1 /* a value to mark a dead process' file descriptors with *//* *** DATA TYPES *** *//* a process address */typedefchar proc_addr;/* a message */struct message_s { proc_addr src_id;shortint length;char*payload;};/* *** FUNCTION PROTOTYPES *** *//* send message to process with id dest */intsend_proc_message(proc_addr dest,char*message);/* receive a message in the process' queue of received ones */intreceive_proc_message(struct message_s *msg);/* mark process file descriptors closed */voidmark_proc_closed(proc_addr process);/* *** GLOBAL VARS *** *//* they are OK to be global here. */proc_addr my_address; /* stores the id of the process */int proc_pipes[PROCS_NUM][2]; /* stores the pipes of every process involved */intmain(int argc,char*argv[]) {pid_t child_pid;pid_t my_children[PROCS_NUM]; /* PIDs of the children */int i, ret;char msg_text[MAX_PAYLOAD_LENGTH]; /* payload of the message to send */ proc_addr msg_recipient;struct message_s msg; /* create a pipe for me (the parent) */pipe(proc_pipes[0]); /* initializing proc_pipes struct */for (i =1; i < PROCS_NUM; i++) { /* creating one pipe for every (future) process */ ret =pipe(proc_pipes[i]);if (ret) {perror("Error creating pipe");abort(); } } /* fork [1..NUM_PROCS] children. 0 is me. */for (i =1; i < PROCS_NUM; i++) { /* setting the child address */ my_address = my_address +1; child_pid =fork();if (!child_pid) { /* child */sleep(1); /* closing other process' pipes read ends */for (i =0; i < PROCS_NUM; i++) {if (i != my_address)close(proc_pipes[i][0]); } /* init random num generator */srandom(time(NULL)); /* my_address is now my address, and will hereby become a "constant" */ /* producing some message for the other processes */while (random()% (2* PROCS_NUM)) { /* interleaving... */sleep((unsignedint) (random() %2)); /* choosing a random recipient (including me) */ msg_recipient = (proc_addr) (random()% PROCS_NUM); /* preparing and sending the message */sprintf(msg_text,"hello from process %u.", (int) my_address); ret =send_proc_message(msg_recipient, msg_text);if (ret >0) { /* message has been correctly sent */printf(" --> %d: sent message to %u\n", my_address, msg_recipient); } else { /* the child we tried to message does no longer exist */mark_proc_closed(msg_recipient);printf(" --> %d: recipient %u is no longer available\n", my_address, msg_recipient); } } /* now, reading the first 2 messages we've been sent */for (i =0; i <2; i++) { ret =receive_proc_message(&msg);if (ret <0)break;printf("<-- Process %d, received message from %u: \"%s\".\n", my_address,msg.src_id,msg.payload); }; /* i'm exiting. making my pipe widowed */close(proc_pipes[my_address][0]);printf("# %d: i am exiting.\n", my_address);exit(0); } /* saving the child pid (for future killing) */ my_children[my_address] = child_pid; /* parent. I don't need the read descriptor of the pipe */close(proc_pipes[my_address][0]); /* this is for making srandom() consistent */sleep(1); } /* expecting the user request to terminate... */printf("Please press ENTER when you like me to flush the children...\n");getchar();printf("Ok, terminating dandling processes...\n"); /* stopping freezed children */for (i =1; i < PROCS_NUM; i++) {kill(my_children[i], SIGTERM); }printf("Done. Exiting.\n");return0;}intsend_proc_message(proc_addr dest,char*message) {int ret;char*msg = (char*) malloc(sizeof(message) +2); /* the write should be atomic. Doing our best */ msg[0] = (char) dest;memcpy((void*) &(msg[1]), (void*) message, strlen(message) +1); /* send message, including the "header" the trailing '\0' */ ret =write(proc_pipes[dest][1], msg, strlen(msg) +2);free(msg);return ret;}intreceive_proc_message(struct message_s *msg) {char c ='x';char temp_string[MAX_PAYLOAD_LENGTH];int ret, i =0; /* first, getting the message sender */ ret =read(proc_pipes[my_address][0],&c,1);if (ret ==0) {return0; }msg->src_id = (proc_addr) c;do { ret =read(proc_pipes[my_address][0],&c,1); temp_string[i++] = c; } while ((ret >0) && (c !='\0') && (i < MAX_PAYLOAD_LENGTH));if (c =='\0') { /* msg correctly received. Preparing message packet */msg->payload = (char*) malloc(strlen(temp_string) +1);strncpy(msg->payload, temp_string, strlen(temp_string) +1);return0; }return-1;}voidmark_proc_closed(proc_addr process) { proc_pipes[process][0] = DEAD_PROC; proc_pipes[process][1] = DEAD_PROC;}
$ gcc --ansi --pedantic -o pipe4 pipe4.c
$ ./pipe4
--> 1: sent message to 3
--> 1: sent message to 8
--> 2: sent message to 0
--> 1: sent message to 5
--> 2: sent message to 4
--> 1: sent message to 10
--> 2: sent message to 9
--> 2: sent message to 0
--> 3: sent message to 11
--> 2: sent message to 6
--> 1: sent message to 2
--> 2: sent message to 12
--> 3: sent message to 14
<-- Process 4, received message from 4: "hello from process 2.".
--> 3: sent message to 13
--> 1: sent message to 3
--> 1: sent message to 9
--> 1: sent message to 12
--> 1: sent message to 3
--> 2: sent message to 6
--> 3: sent message to 7
<-- Process 5, received message from 5: "hello from process 1.".
--> 2: sent message to 12
--> 2: sent message to 5
--> 1: sent message to 7
--> 1: sent message to 4
<-- Process 4, received message from 0: "hello from process 1.".
# 4: i am exiting.
--> 1: sent message to 12
--> 1: sent message to 2
<-- Process 5, received message from 0: "hello from process 2.".
# 5: i am exiting.
--> 2: sent message to 14
--> 2: sent message to 1
--> 2: sent message to 10
--> 1: sent message to 8
--> 1: sent message to 0
--> 1: sent message to 0
--> 6: sent message to 13
--> 6: sent message to 8
--> 6: sent message to 14
--> 8: sent message to 14
--> 6: sent message to 14
--> 8: sent message to 8
--> 8: sent message to 11
--> 9: sent message to 14
--> 10: sent message to 0
^C