管道具有以下特点:
(1)半双工。数据只能在一个方向上流动。
(2)只能在具有公共祖先的进程间使用。通常,一个管道由一个进程创建,然后该进程调用fork,此后父子进程间就可应用该管道。
(3)单独构成一种独立的文件系统。管道对于管道两端的进程而言就是一个文件,但它不是变通的文件,而是单独构成一种文件系统,并且只存在于内存中。
(4)数据从管道的一端写入,但从另一端读出。一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出。
(5)没有名字。
(6)管道的缓冲区是有限的(管道存在于内存中,在管道创建时,为缓冲区分配一个页面大小)。
(7)管道传送的数据是无格式的。
(8)写入管道的数据读完后就从管道中消失。
管道的创建和读写
一个进程在由pipe()创建管道后,一般再fork一个子进程,然后通过管道实现父子进程间的通信。
#include <unistd.h>
int pipe(int fd[2])
管道两端可分别用描述字fd[0]和fd[1]来描述,一端只能用于读,由描述字fd[0]表示(管道读端);另一端则只能用于写,由描述字fd[1]来表示(管道写端)。
使用管道的C程序实例:父子进程间建了两个管道,用于相互读写对方的信息。
#include <unistd.h>
#include <sys/types.h>
int main(void)
{
int pipe1_fd[2], pipe2_fd[2];
char * parent_talks[] = {"Hi, my baby",
"Can you tell daddy date and time?",
"Daddy have to leave here, bye!",
NULL
};
char * child_talks[] = {"Hi, daddy",
"Sure,",
"Bye!",
NULL
};
char parent_buf[256], child_buf[256];
char * parent_ptr, * child_ptr;
int i,j, len;
int child_status;
time_t curtime;
if(pipe(pipe1_fd)<0)
{
printf("pipe1 create error\n");
return -1;
}
if(pipe(pipe2_fd)<0)
{
printf("pipe2 create error\n");
return -1;
}
if(fork()==0) //child
{
printf("\n");
//pipe1_fd[0] is used to read, pipe2_fd[1] is used to write
close(pipe1_fd[1]);
close(pipe2_fd[0]);
i = 0;
child_ptr = child_talks[i];
while(child_ptr != NULL)
{
len = read(pipe1_fd[0], child_buf, 255);
child_buf[len] = '\0';
printf("Parent: %s\n", child_buf);
if (i == 1) {
time(&curtime);
len = sprintf(child_buf, "%s %s", child_ptr, ctime(&curtime));
child_buf[len-1] = '\0';
write(pipe2_fd[1], child_buf, strlen(child_buf));
}
else {
write(pipe2_fd[1], child_ptr, strlen(child_ptr));
}
child_ptr = child_talks[++i];
}
close(pipe1_fd[0]);
close(pipe2_fd[1]);
exit(0);
}
else { //parent
//pipe1_fd[1] is used to write, pipe2_fd[0] is used to read
close(pipe1_fd[0]);
close(pipe2_fd[1]);
j = 0;
parent_ptr = parent_talks[j];
while (parent_ptr != NULL) {
write(pipe1_fd[1],parent_ptr,strlen(parent_ptr));
len = read(pipe2_fd[0],parent_buf,255);
parent_buf[len] = '\0';
printf("Child: %s\n", parent_buf);
parent_ptr = parent_talks[++j];
}
close(pipe1_fd[1]);
close(pipe2_fd[0]);
wait(&child_status);
exit(0);
}
}
管道函数
#include <stdio.h>
FILE *popen(const char *cmdstring, const char *type);
int pclose(FILE *fp);
用于计算简单的数学表达式的shell脚本calculator
#filename: calculator
#!/bin/sh
while :
do
read expression
expression=`echo "$expression" | sed 's/\*/\\\*/'`
if [ "$expression" = "" ] ; then
exit
fi
eval "expr $expression"
done
下面的程序使用popen来执行calculator脚本:先接收用户输入的表达式,然后通过popen打开的文件句柄传送给该脚本,脚本将执行该表达式并把结果输出到标准输出。输入quit退出程序。
#include <stdio.h>
#include <string.h>
int main(void)
{
char buf[256];
FILE * fp = popen("./calculator", "w");
if ( fp == NULL) {
printf("Fail to poen ./calculator...\n");
exit(-1);
}
while (1) {
printf("Enter a expression: ");
fgets(buf, 256, stdin);
if (strncmp("quit", buf, 4) == 0) {
fprintf(fp, "\n");
fflush(fp);
pclose(fp);
exit(0);
}
fprintf(fp, "%s", buf);
fflush(fp);
sleep(1);
}
}
注:输入表达式时,运算符两端要有空格
(studyarea) |