管道定义
什么是管道
管道是Unix中最古老的进程间通信的形式。
我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”
我们通常把是把一个进程的输出连接或“管接”(经过管道来连接)到另一个进程的输入
在shell中使用管道
链接shell命令:把一个进程的输出直接馈入另一个的输入,命令格式如下
cmd1 | cmd2
cmd1的标准输入来自终端键盘
cmd1的标准输出馈入cmd2做为它的标准输出
cmd2的标准输出连接到终端屏幕上
shell所做的工作从最终效果上看是这样的:重新 安排标准输入和输出流之间的连接,使数据从键 盘输入流过两个命令再输出到屏幕
管道特点
管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道
也就是说假设有一个a进程和b进程,在二者之间设置一个管道要么a写b接收,要么b写a接收,不
能a写b也写,或者a接收b也接收,这样会导致管道创建不成功,要想使双方都能接收和写只能创
建两个管道进行通信
管道的分类
匿名管道
只用于具有亲缘关系进程之间
命名管道
任何进程都可用
匿名管道
只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程)进行通信;通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道
pipe函数
包含头文件<unistd.h>
功能:创建一无名管道
原型:int pipe(int file_descriptor[2]);
参数 file_descriptor:文件描述符数组,其中file_descriptor[0]表示读端,file_descriptor[1]表示写端
返回值:成功返回0,失败返回错误代码
void test02()
{
int fdArr[2] = { 0 };
int pid = 0;
//匿名管道 数据承载量65535 64kb
int pipRes = pipe(fdArr);
if (pipRes != 0)
{
perror("pipe error:");
}
else {
pid = fork();
//父给子传数据 父是源头用写 关闭读 子是目的地用读 关闭写
if (pid > 0)
{
STU stu = { 0 };
char buf[20] = { "hello world" };
//父->子 关闭读端 使用写
close(fdArr[0]);
for (int i = 0; i < 5; i++)
{
stu.stuId = 1001 + i;
sprintf(stu.stuName, "张三%d", i);
stu.stuGrade = 85.5 + i;
int res = write(fdArr[1], &stu, sizeof(STU));
cout << "父进程 写出数据 res = " << res << endl;
sleep(1);
}
}
else if (pid == 0)
{
STU stu = { 0 };
char resBuf[20] = { 0 };
//子->父 关闭写段 使用读
close(fdArr[1]);
while (true)
{
int res = read(fdArr[0], &stu, sizeof(STU));
cout << "子进程 读取数据内容 stu.stuId = " << stu.stuId << endl;
cout << "子进程 读取数据内容 stu.stuName = " << stu.stuName << endl;
cout << "子进程 读取数据内容 stu.stuGrade = " << stu.stuGrade << endl;
}
}
}
while (true)
{
}
}
特别注意再确定好那个进程是写端,那个进程是读端,然后在进程当中将其给不需要的关闭
命名管道
管道应用的一个限制就是只能在相关的程序之间进行,这些程序是由一个共同的祖先进程启动的。
如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。
命名管道是一种特殊类型的文件
FIFO文件
命名管道可以从命令行上创建,推荐的命令行方法是使用下面这个命令:
$ mkfifo filename
命名管道也可以从程序里创建,相关函数有:
int mkfifo(const char *filename,mode_t mode);
int mknod(const char *filename,mode_t mode|S_IFIFO, dev_t) 0);
但需要注意的是这两个创建文件时不会判断是否有之前原有的文件,因此在做这步操作前可以加个判定,access函数可以判断
int access(const char *pathname, int mode);
F_OK:用于检查文件是否存在。
R_OK:用于检查是否具有读取权限。
W_OK:用于检查是否具有写入权限。
X_OK:用于检查是否具有执行权限
设置两个工程一个工程a
void test01()
{
char buf[100] = { 0 };
if (access("/root/projects/A2B.fifo", F_OK) == -1)
{
umask(0);
if (mkfifo("/root/projects/A2B.fifo", 0777) == -1)
{
perror("mkfifo error:");
return;
}
else
{
cout << "A2B.fifo文件创建成功" << endl;
}
}
else
{
cout << "文件已存在,直接打开文件即可" << endl;
}
int wfd = open("/root/projects/A2B.fifo", O_WRONLY);
while (true)
{
cin >> buf;
int wres = write(wfd, buf, sizeof(buf));
cout << "wres = " << wres << endl;
}
}
一个工程b
void test01()
{
char buf[100] = { 0 };
if (access("/root/projects/A2B.fifo", F_OK) == -1)
{
umask(0);
if (mkfifo("/root/projects/A2B.fifo", 0777) == -1)
{
perror("mkfifo error:");
return;
}
else
{
cout << "A2B.fifo文件创建成功" << endl;
}
}
else
{
cout << "文件已存在,直接打开文件即可" << endl;
}
int rfd = open("/root/projects/A2B.fifo", O_RDONLY);
while (true)
{
int rres = read(rfd, buf, sizeof(buf));
cout << "rres = " << rres << "buf = " << buf << endl;
if (rres == 0)
{
break;
}
}
}
a进程负责写入,b进程负责读取,而在创建完fifo文件之后后续的内容就如同文件读写操作一样,a进程负责写入b进程负责读取
需要注意的是,fifo文件并不是a将内容写入到这里面,并在到fifo文件内进行读取,更像是一个桥梁,使两个没有情缘关系的进程之间能够进行数据的传输
标签:OK,int,fifo,mkfifo,管道,进程 From: https://blog.csdn.net/2301_80441410/article/details/142420545