管道知识整理

管道:

匿名管道(必须是亲缘进程)

单工管道:

FIFE *popen (const char * command ,const char *type );

popen() 函数通过创建一个管道,调用 fork 产生一个子进程,执行一个 shell 来开启一个进程。这个进程必须由 pclose() 函数关闭,popen()和pclose()配套使用。

type参数只能是读或者写中的一种,得到的返回值(标准 I/O 流)也具有和 type相应的只读或只写类型。

返回值:如果调用 fork() 或 pipe() 失败,或者不能分配内存将返回NULL,否则返回标准 I/O 流

特点:能够方便使用系统自带的功能,可以执行比较复杂的shell,但是默认启动两个进程,效率比较低。

例子:

#include <sys/types.h>  
#include <unistd.h>  
#include <stdlib.h>  
#include <stdio.h>  
#include <string.h>
int main( void )  
{  
    FILE   *stream;  
    FILE    *wstream;
    char   buf[1024]; 

 memset( buf, '/0', sizeof(buf) );//初始化buf
    stream = popen( "ls -l", "r" ); //将“ls -l”命令的输出 通过管道读取(“r”参数)到FILE* stream
    wstream = fopen( "test_popen.txt", "w+"); //新建一个可写的文

 fread( buf, sizeof(char), sizeof(buf),  stream); //将刚刚FILE* stream的数据流读取到buf中
   fwrite( buf, 1, sizeof(buf), wstream );//将buf中的数据写到FILE *wstream对应的流中,也是写到文件中
    
    pclose( stream );  
    fclose( wstream );
    
    return 0;
}   

半双工管道:

int pipe(int fd[2]);

返回值: 若成功则返回零,否则返回-1。

fd[0]为管道里的读取端

fd[1]则为管道的写入端

简记:零下一度反过来

在打开读入端和写入端后在程序结束之前关闭两个端口。

注:当管道为空时,读进程阻塞,如果管道为满时,写进程阻塞。

例子:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

 

int main(){

int fd[2];

pipe(fd);

if(!fork()){// child

char in[] = "Hello pipe";

sleep(3);

write(fd[1],in,sizeof(in));

printf("child %d write:%s\n",getpid(),in);

}else{// parent

char out[BUFSIZ]={0};

ssize_t n = read(fd[0],out,sizeof(out));

if(-1 == n){

perror("read error");

return -1;

}

printf("parent %d read:%s\n",getpid(),out);

}

close(fd[0]);

close(fd[1]);

}

文件描述符和文件流指针的区别:

 

dup函数:

int dup(int oldfd);

dup函数用来复制一个描述符。传给该函数一个述符,它就会返回一个新的描述符,这个新的描述符是传给它的描述符的拷贝如:fd2=dup(fd1)。

dup2函数:

dup2(int oldfd,int newfd);

dup2函数也是复制描述符,dup2函数允许调用者规定一个有效描述符和目标描述符的id。dup2函数成功返回时,目标描述符(dup2函数的第二个参数)将变成源描述符(dup2函数的第一个参数)的复制品newfd已经被程序使用,系统将其关闭释放该文件描述符。

注意:dup2函数在复制了oldfd之后,会立即将其关闭

例子:

原文件test内容为:hhhhhhhhhhhh
int main()
 {
   int oldfd;

   oldfd = open("test",O_RDWR|O_CREAT,0644);
   dup2(oldfd,1);   //复制oldfd到文件描述符1(stdout标准输出)
   close(oldfd);    //关闭文件描述符oldfd
   printf("ggg");  //在标准输出上打印出ggg,这时由于标准输出已经被oldfd文件描述符代替
   return 0;       //打印到标准输出上的内容就全部打印到了文件test中
 }

执行完成后结果test内容变为:ggghhhhhhhhh

FIFO管道(命名管道):  

int mkfifo(const char * pathname,mode_t mode):

   mkfifo作用是在文件系统中创建一个文件,此文件必须不存在,该文件用于提供FIFO功能,即命名管道,命名管道是一个可见的文件,它可以用于任何两个进程之间的通信,不管这两个进程是不是父子进程,也不管这两个进程之间有没有关系。

参数:第一个参数(pathname)是将要在文件系统中创建的一个专用文件。第二个参数(mode)用来规定FIFO的读写权限。Mkfifo函数如果调用成功的话,返回值为0;如果调用失败返回值为-1

管道创建例子mkfifo("/tmp/test",0644)):/tmp下创建文件名为test的FIFO文件,权限为0644。

写入命名管道:

int main(){

int fd = open("/tmp/test",O_WRONLY|O_NONBLOCK);

if(-1 == fd){

perror("open error");

return 1;

}

char str[] = "Hello fifo";

write(fd,str,sizeof(str));

printf("write:%s\n",str);

}

读取与写入类似。

注:1.fifowrite与fiforead要同时执行,才会数据传递。否则会造成阻塞。

1. fcntl(fd,F_SETFL,O_NONBLOCK)不能控制命名管道读写阻塞问题。必须在open命名管道时,指定非阻塞打开。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值