无名管道概念
默认情况下,一个进程默认打开3个设备文件,标准输入,标准输出,标准错误
//从标准输入(键盘)输入了ls,它的标准输出作为标准输入传到下一个进程
//grep 命令从上一个命令ls的输出寻找linux的字符
//因此实现了进程之间的通信
[yqtao@localhost ~]$ ls | grep linux
linux
无名管道是一种特殊的文件,在内核中对应的资源是一段特殊的内存空间。这段空间由操作系统管理和维护。注意其不能使用lseek()函数来修改当前的读写位置,因为管道满足FIFO原则。
无名管道文件操作
//fd[0]为读而打开,fd[1]为写而打开
//即fd[1]的输入是fd[0]的输出
#incude<unistd.h>
int pipe(int fd[2])
1. 以阻塞方式读无名管道
如果但却没有一个进程访问写端,则读操作立即返回,并按如下操作:
如果管道无数据,立即返回0
如果有数据大于要读的数据,立即读出所要读的大小
如果有数据小于要读的数据,读取所有的数据
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include<string.h>
int main(){
int p[2];
pipe(p);
close(p[1]); //close write way
char buf[128];
memset(buf,'\0',128);
int ret=-1;
ret=read(p[0],buf,128);
printf("buf=%s\n",buf);
}
运行后的结果:
因为管道中没有数据立即返回。
buf=
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include<string.h>
int main(){
int p[2];
pipe(p);
write(p[1],"helloworld",10); //向写端写入数据
close(p[1]); //close write way
char buf[128];
memset(buf,'\0',128);
int ret=-1;
ret=read(p[0],buf,3); //read 3
printf("ret=%d,buf=%s\n",ret,buf);
ret=read(p[0],buf,15); //read 15
printf("ret=%d,buf=%s\n",ret,buf);
}
下面为运行结果:
[yqtao@localhost linux]$ gcc -o pipe pipe.c
[yqtao@localhost linux]$ ./pipe
ret=3,buf=hel
ret=7,buf=loworld //注意这里不是helloworld
2. 以阻塞方式读无名管道
如果当前没有任何一个进程可以访问读端,则写操作将收到SIGPIPE信号,write函数返回-1.如果当前有进程可以访问读端,且管道有空间,则写入成功。
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include<string.h>
5 #include<signal.h>
6 void hander(int sig) {
7 if (SIGPIPE==sig)
8 printf("recv SIGPIPE\n");
9 }
10 int main(){
11 int p[2];
12 pipe(p);
13 signal(SIGPIPE,hander);
14 close(p[0]);
15 int ret=-1;
16 ret=write(p[1],"helloworld",10);
17 printf("ret=%d\n",ret);
18 }
运行结果如下:
[yqtao@localhost linux]$ gcc -o pipe pipe.c
[yqtao@localhost linux]$ ./pipe
recv SIGPIPE
ret=-1
文件描述符重定向
重定向的基本操作
//输入重定向,其中test01中以写入内容,将其内容定向cat显示
//等于cat test01
[yqtao@localhost linux]$ cat < test01
hello world
//将标准输出重定向到test02文件,输入重定向到test01
//test01必须存在 ,test02不必存在
//若test02存在则覆盖,以追加方式可用 >>
cat >test02 <test01 //等价于cat <test01 >test02
//&表示联合,则标准错误2也将输出在标准输出test02中
//test02中文件的内容为: 1 -bash: test01: No such file or directory
[yqtao@localhost linux]$ ls -l test01 test02
ls: cannot access test01: No such file or directory
ls: cannot access test02: No such file or directory
[yqtao@localhost linux]$ cat > test02 2>&1 <test01
重定向编程
因为普通输出函数(printf)默认的是将信息写入文件描述符为1的文件中(一般是标准输出),普通输入函数从文件描述符为0读数据。
因此重定向操作实际上是关闭某个标准输入输出设备(文件描述符0,1,2),而将另一个打开的普通文件描述符设置成0,1,2
dup,dup2复制文件描述符。
int fd[2];
pipe(fd);
close(fileno(stdout));
dup(fd[1]); //返回最低的可用文件描述符
//如果fd2存在,则关闭,然后将fd复制给fd2
dup2(fd,fileno(stdout));
流重定向
前面为使用文件描述符来实现重定向操作。
标准I/O提供如下函数实现流重定向.
#include<stdio.h>
//popen创建一个子进程,并在子进程中执行第一个参数所指是的程序
//同时返回一个文件指针,第二个参数为I/O方式
FIFE *popen(const char *cmdsting,const char *type);
int pclose(FILE* fp);
一个列子,相当于 echo test | cat
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <string.h>
4 #include <stdlib.h>
5 int main() {
6 FILE *finput,*foutput;
7 char buffer[1024];
8 finput=popen("echo test","r");
9 foutput=popen("cat","w");
10 read(fileno(finput),buffer,strlen("test"));
11 write(fileno(foutput),buffer,strlen("test"));
12 pclose(finput);
13 pclose(foutput);
14 printf("\n");
15 return 0;
16 }
运行结果:
[yqtao@localhost linux]$ gcc -o popen popen.c
[yqtao@localhost linux]$ ./popen
test