前言
Linux进程间通信(IPC)的一个重要方法就是管道,在学习管道之前,要理解两个概念
- 半双工(读端与写端必须固定)
- 全双工(读端与写端不固定)
不论是无名管道还是有名管道,都属于半双工管道,理解这一点非常重要。
一.标准管道流
FILE *popen(const char *__command, const char *__modes)
command 代表shell指令
modes 分为 "r"读 和 "w"写
具体功能和Linux命令中的管道基本相同
void test1()
{
//读
FILE *fp = popen("cat /etc/profile", "r");
char buf[1000] = {0};
while (fread(buf, sizeof(char), sizeof(buf), fp))
cout << buf;
cout << endl;
pclose(fp);
//写
char buf2[] = {"aaa bbb ccc ddd eee fff ggg hhh"};
FILE *fp2 = popen("wc -w", "w");
fwrite(buf2, sizeof(char), sizeof(buf2), fp2);
pclose(fp2);
}
二.无名管道
- 只能在亲缘进程之间使用
- 为半双工管道(即只能一端读,一端写)
- 无名管道是特殊的文件,只能存在于内存中
注意:无名管道中的 read
函数会进行阻塞。
案例:创建一个无名管道 与 父子进程,进行父写子读
void test2()
{
int fds[2] = {0};
pipe(fds);//fds[0] = 3, fds[1] = 4;
if (fork() == 0)
{
close(fds[1]);
char buf[100] = {0};
read(fds[0], buf, sizeof(buf));
cout << "child process reading:" << buf << endl;
close(fds[0]);
exit(0);
}
close(fds[0]);
char buf[100] = "Helloworld";
write(fds[1], buf, strlen(buf));
cout << "father process is writing" << endl;
close(fds[1]);
wait(NULL);
}
三.命名管道
命名管道比起无名管道,即便不是亲属进程也能够进行进程间通信
另外,命名管道可以作为文件存在。
需要使用 mkfifo
命令创建命名管道
命名管道:读写操作案例
分别创建好 读端
与 写端
, 并设置退出机制
注意:如果没有设置退出机制,那么read端 将会默认一直在接收 0 个字符,读端将会一直打印空字符串
写端 (write.cpp)
:
int main()
{
int fdw = open("pipe", O_WRONLY);
ERROR_CHECK(fdw, -1 ,"open w");
char buf[100] = {0};
while (1)
{
memset(buf, 0, sizeof(buf));
read(0, buf, sizeof(buf));
write(fdw, buf, strlen(buf) - 1);
}
return 0;
}
读端(read.cpp)
:
int main()
{
int fdr = open("pipe", O_RDONLY);
ERROR_CHECK(fdr, -1, "open r");
char buf[100] = {0};
int ret;
while (1)
{
memset(buf, 0, sizeof(buf));
ret = read(fdr, buf, sizeof(buf));
if (ret == 0)
{
cout << "byebye" << endl;
break;
}
cout << "ret = " << ret << endl;
cout << "buf = " << buf << endl;
}
return 0;
}
通过以上程序,可以实现一端写,一段读的案例。