进程间通信--管道

无名管道概念

默认情况下,一个进程默认打开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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值