传统的进程间通信——管道通信
传统的进程间通信——管道通信
-
管道是UNIX系统中最古老的进程间通信方式,是一种特殊文件读写机制
-
当进程从管道文件中读取数据时,如果管道中没有数据则进程会进入阻塞状态,直到有数据读取出来才返回,因此不需要借助信号、文件锁来协调读写时间
-
管道中的数据一旦读取完毕就会消失,因此也不需要管理文件的位置指针,所以使用管道文件比普通文件的进程间通信要方便很多
-
古老的好处是所有系统都支持,早期的管道文件是半双工,现在有些系统支持管道文件的全双工,现在绝大多数情况已经不使用管道来通信了
有名管道:
-
在文件系统中创建出一个实体的有文件名的管道文件,然后通过系统I/O的相关API来进行相关操作
使用函数创建:
#include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *pathname, mode_t mode); 功能:创建一个有名管道文件 pathname:管道文件的名字 mode:管道文件的权限 返回值:成功返回0 失败-1
使用命令创建:
mkfifo <file>
管道单向通信的编程模型:
进程A -> 进程B 创建有名管道 打开管道 打开管道 写数据 读数据 关闭管道 关闭管道 删除管道
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc,const char* argv[])
{
// 创建管道文件
if(mkfifo("fifo",0644))
{
perror("mkfifo");
return -1;
}
// 打开管道
int fd = open("fifo",O_WRONLY);
if(0 > fd)
{
perror("open");
unlink("fifo");
return -1;
}
char buf[256] = {};
for(;;)
{
printf(">>>");
// 使用封装好的my_gets()
gets(buf);
// 写文件 发送数据
write(fd,buf,strlen(buf));
// 检查是否quit
if(0 == strcmp(buf,"quit"))
{
printf("通信结束\n");
usleep(1000);
break;
}
}
// 关闭管道
close(fd);
// 删除管道
unlink("fifo");
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc,const char* argv[])
{
// 打开管道
int fd = open("fifo",O_RDONLY);
if(0 > fd)
{
perror("open");
return -1;
}
char buf[256] = {};
// 读数据
for(;;)
{
read(fd,buf,sizeof(buf));
printf("read:%s\n",buf);
if(0 == strcmp(buf,"quit"))
{
printf("通信结束\n");
break;
}
}
// 关闭管道
close(fd);
}
匿名管道:
-
只在内核中创建的管道文件对象并返回该对象的文件描述符,然后使用系统IO进行相关操作,匿名管道文件不会在文件系统中显示,在创建时不需要提供路径,也不会占用磁盘空间,只是使用内核空间来临时存储数据,当关闭文件描述符后会自动回收
-
注意:只适合fork创建的有关系的父子进程之间进行通信
相关API:
#include <unistd.h>
int pipe(int pipefd[2]);
功能:创建出匿名管道文件对象,并返回该对象的文件描述符
pipefd:输出型参数,用于存储文件描述符的数组,其中
pipefd[0] 用于读操作
pipefd[1] 用于写操作
使用步骤:
1、调用该函数在内核中创建出管道文件,并获取到该文件的两个文件描述符
2、通过fork创建出子进程,子进程可以直接拷贝父进程的pipefd描述符
3、写数据的进程要关闭读端,读数据的进程要关闭写端
4、发送完毕后,父子进程分别关闭文件描述符
编程模型:
父进程 -> 子进程 创建匿名管道 创建子进程 拷贝一对fd 关闭读端(fd[0]) 关闭写端(fd[1]) 写数据(fd[1]) 读数据(fd[0]) 关闭写 关闭读
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc,const char* argv[])
{
// 创建匿名管道
int fd[2] = {};
if(pipe(fd))
{
perror("pipe");
return -1;
}
// 创建子进程
if(fork())
{
// 父进程 负责写 关闭读
close(fd[0]);
char buf[256] = {};
for(;;)
{
printf("父进程>>>");
gets(buf);
write(fd[1],buf,strlen(buf));
if(0 == strncmp(buf,"quit",4))
{
printf("通信结束\n");
break;
}
usleep(1000);
}
usleep(1000);
close(fd[1]);
usleep(1000);
}
else
{
// 子进程 负责读 关闭写
close(fd[1]);
char buf[256] ={};
for(;;)
{
read(fd[0],buf,sizeof(buf));
printf("read:%s\n",buf);
if(0 == strncmp(buf,"quit",4))
{
printf("父进程要结束通信\n");
break;
}
}
close(fd[0]);
}
}