Linux 学习笔记15 管道
在 linux IPC (进程间通信)中,管道通信又有三种类型,分别为标准流管道,无名管道和有名管道。
- 标准流管道
FILE* popen(const char* command, const char* open_mode);
int pclose(FILE* fp);`
函数 popen():允许一个程序将另一个程序作为新进程来启动,并可以传递数据给它或者通过它接收数据。
command 字符串是要运行的程序名。
open_mode 必须是“r”或“w”。
如果 open_mode 是“r”,被调用程序的输出就可以被调用程序(popen)使用,调用程序利 popen 函数返回的 FILE*文件流指针,就可以通过常用的 stdio 库函数(如 fread)来读取被 调用程序的输出;如果 open_mode 是“w”,调用程序(popen)就可以用 fwrite 向被调用程序发送数据,而被调用程序可以在自己的标准输入上读取这些数据。
popen原理如下:
例:
#include <func.h>
//标准流管道
//
int main()
{
FILE *fp;
fp=popen("./print","r");
//fp=popen("ls -l","r");//for test command也可以是命令 ls -l
ERROR_CHECK(fp,NULL,"popen");
char buf[1024]={0};
fread(buf,sizeof(char),sizeof(buf),fp);
printf("popen:%s",buf);
pclose(fp);
return 0;
}
print函数如下:
#include <func.h>
int main()
{
printf("I am print elf\n");
return 0;
}
执行效果如下:
- 无名管道pipe
管道实际是内核开辟了一段大小为4K的缓冲区,进程A和B都能往缓冲区里读写。
因此,进程间通信都要借助内核来实现。
无名管道的原理、特点,方法如下所示: - int fds[2]
pipe(fds);
读端fds[0],写端fds[1]
一旦fork(),父子进程都有管道的读写端。
使用时会让一端写一端读。如果想要双向通信,则需要两条管道,int fdss[2]
因此无名管道具有如下特点:
1 只能在亲缘关系进程间通信
2 半双工(固定的读端和固定的写端)
3 他是特殊的文件,可以用 read、write 等,只能在内存中
#include <func.h>
int main()
{
int fds[2];
pipe(fds);//无名管道
printf("fd[0]=%d,fds[1]=%d\n",fds[0],fds[1]);
//默认fds[0]为读端,fds[1]为写端
if(!fork())
{
close(fds[1]);//假设子进程读,关闭写端
char buf[128]={0};
read(fds[0],buf,sizeof(buf));
printf("Child Mark3 buf=%s\n",buf);
exit(0);
}
else
{
close(fds[0]);//父进程写,关闭读端
write(fds[1],"hello",5);
wait(NULL);
return 0;
}
}
执行结果如下:
- 有名管道
int mkfifo(const char *pathname, mode_t mode);
参数解析
pathname 为要创建的 FIFO 文件的全路径名;
mode 为文件访问权限mkfifo
#include <func.h>
//创建一个命名管道文件
int main(int argc,char*argv[])
{
ARGS_CHECK(argc,2);
int ret;
ret=mkfifo(argv[1],0666);//权限为0664
ERROR_CHECK(ret,-1,"mkfifo");
return 0;
}
执行结果如下:
- 删除FIFO文件的函数原型为:
int unlink(const char *pathname);
代码如下:
#include <func.h>
int main(int argc,char*argv[])
{
ARGS_CHECK(argc,2);
int ret;
ret=unlink(argv[1]);
ERROR_CHECK(ret,-1,"unlink");
return 0;
}
执行效果如下: