标准管道流,用于文件流模式
popen();
原型 FILE *popen(char *command,char *type);
//如果调用成功,则返回一个文件流,如果无法创建则返回NULL,该函数主要用于执行外部程序
// command 参数是一个指向以 NULL 结束的 shell 命令字符串的指针。
//其中type参数是用来表示读或者写的,不能同时为读和写,管道将会以参数type的第一个字符代表的方式打开
//popen打开的数据管道流可以使用pclose()关闭, popen,pclose用于打开和关闭数据流
//如果pclose(FILE *stream)调用失败,则返回-1;注意,在使用pclose时并不是立即关闭管道流,而是等待管道流的管道流进程结束才关闭的
例子:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#define BUFSIZE 512 //创建缓冲区字节
int main()
{
char buf[BUFSIZE];
FILE *fp; //创建流文件指针
char *cmd="ls -l"; //定义外部程序已经参数
if((fp=popen(cmd,"r"))==NULL)
{
//返回NULL时表示调用出错,进行出错处理 ,如 perror("popen")
}
while((fgets(buf,BUFSIZE,fp))!=NULL)
/*
fgets(char * s,int size,FILE * stream);
括号中,第一个参数为将被赋值的数组名,这里需要注意的是,其中不用写数组名
称后面的方括号以及其中的数组长度。
第二个参数是将要读取字符串的长度,这里需要注意的是,这里长度的数值是“字
符串实际长度+1”,加1是因为,字符串最后面还有一个/0位。这个参数只是期望读取的最大数,并不是一定要读取到size个字节才会返回
最后一个参数为输入设备或者变量或者一个文件流,本例子中使用了管道文件流
*/
printf("%s",buf); //输出读取到的字符
//实际的输出结果相当于在linux的shell里敲击了ls -l指令
pclose(fp); //关闭文件流管道,使用popen创建的文件流管道必须使用pclose关闭!!
exit(0);
}
命名管道 FIFO
命名管道不存在于内存中,而是在文件系统中作为一个特殊的设备文件存在的,它可以用于两个不同祖先的进程之间的通讯(例如非父子进程,这是和pipe的最大区别)
例如将命名管道创建的文件放在/tmp下时,在计算机重启动之前是不会消失的,即使该进程已经关闭
命名管道的创建
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname,mode_t mode);
//pathname是路径名,mode是创建方式,一旦使用mkfifo创建了命名管道,则可以使用open函数打开它,和标准的文件操作时相同
//mode可以设置为非阻塞和阻塞方式,如果使用阻塞方式,则写命令只有等到另外一个进程读取该管道数据时才继续执行,而读设置为阻塞方式时,只有等到另一个进程向该管道写入数据时才能继续执行
//mkfifo ()会依参数pathname建立特殊的FIFO文件,该文件必须不存在
//返回值
// 若成功则返回0,否则返回-1,错误原因存于errno中。
// 错误代码
// EACCESS 参数pathname所指定的目录路径无可执行的权限
// EEXIST 参数pathname所指定的文件已存在。
// ENAMETOOLONG 参数pathname的路径名称太长。
// ENOENT 参数pathname包含的目录不存在
// ENOSPC 文件系统的剩余空间不足
// ENOTDIR 参数pathname路径中的目录存在但却非真正的目录。
// EROFS 参数pathname指定的文件存在于只读文件系统内。
//例子 :
//读命名管道
#include <sys/types.h>
#include <sys/stat.h>
#include <fontl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FIFO /tmp/tmpfifo //命名管道的路径名,读写管道必须一样
int main(void)
{
char buf_r[100];
int fd;
int nread;
mkfifo(FIFO,O_CREAT|O_EXCL); //创建命名管道,放在FIFO路径,O_CREAT是创建,O_EXCL是可执行
memset(buf_r,0x00,sizeof(buf_r)); //情况数组
fd=open(FIFO,O_RDONLY|O_NONBLOCK,0); //只读方式并且采用非阻塞打开FIFO路径的文件
if(fd==-1)
{
//出错处理
}
while(1)
{
if((nread=read(fd,buf_r,100))==-1){//采用标准文件的读取方式
//读取出错处理
}
sleep(1);
//由于采用了非阻塞方式,这里休眠1秒,则表示每过1s读一次管道
printf("%s\n",buf_r); //打印读到的数据
}
unlink(FIFO); //这一句暂时是执行不到的,unlink()会删除参数pathname指定的文件。如果该文件名为最后连接点,但有其他进程打开了此文件,则在所有关于此文件的文件描述词皆关闭后才会删除。
}
//写命名管道
#include <sys/types.h>
#include <sys/stat.h>
#include <fontl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FIFO /tmp/tmpfifo //命名管道的路径名
int main(int argc,char ** argv) //带参数输入
{
char buf_w[100];
int fd;
int nwrite;
if(argc!=2)
{
//表示用户只打了命令而没有跟参数,则进行出错处理
//本例子中是需要用户打入参数的
}
memset(buf_w,0x00,sizeof(buf_w)); //情况数组
fd=open(FIFO,O_WRONLY|O_NONBLOCK,0); //读写方式并且采用非阻塞打开FIFO路径的文件
//在一般情况下,都是读管道进程先运行的,所以命名管道已经创建了管道文件,所以在写管道时可以直接使用
//open打开读管道创建的管道文件,而不需要使用mkfifo进行创建管道
if(fd==-1)
{
//出错处理
}
strcpy(buf_w,argv[1]); //将用户打入的第一个参数复制给buf_w
if((nwrite=write(fd,w_buf,100))==-1) //写管道操作
{
//写管道错误的出错处理
}
printf("write %s to the FIFO\n",buf_w); //信息回显
}