IPC进程通信---管道

管道是一种进程间通信(IPC)机制,用于在不同进程之间传输数据。它是一种特殊的文件,可以在文件描述符的基础上进行读取和写入操作。

管道分类:

1.匿名管道:只能使用在具有亲缘关系的进程之间进行通信,父子,兄弟,…

2.命名(有名管道):无论是否有亲缘关系的进程都可以进行通信(用于两个项目之间的通信)

  • 参数
    • file_descriptor:文件描述符数组,其中
    • file_descriptor[0]表示读端,file_descriptor[1]表示写端
  • 返回值:成功返回0,失败返回错误代码

管道是半双工,只支持单向传输,因此要在AB进程间要想利用管道达到信息交互的话就必须得建立两个管道,如下图:

我们这边主要对两个.cpp之间的管道通信做解释(命名管道)

  • 在打开FIFO文件时需要注意一个问题:即程序不能以O_RDWR模式打开FIFO文件进行读写

在双进程之间的命名管道传输数据的过程中和管道无关,在打开这个管道之后,即使删除这个fifo文件也可以使用,这个文件只是起到一个命名的作用和创建命名管道的标识,这有点过河拆桥的感觉

下面是代码示例

项目一:pipe

#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
using namespace std;
//命名管道
int main()
{
	//1.要先创建一个文件,创建特殊文件用mkfifo,不能用open创建文件
	umask(0);
	pid_t pid = 0;
	pid = fork();
	if (pid == 0)//子进程,只做数据发送,键盘的数据写入到管道中,管道给到另一个进程,因此要用write
	{
		if (access("/root/projects/A2B.fifo", F_OK))//先判断文件是否存在
		{
			if (mkfifo("/root/projects/A2B.fifo", 0777) == -1)
			{
				perror("mkfifo error");
			}
			else
			{
				cout << "A2B.fifo文件创建成功" << endl;
			}
		}
		else
		{
			cout << "A2B.fifo文件已经存在" << endl;
		}
		int wfd = 0;
		wfd = open("/root/projects/A2B.fifo", O_WRONLY);
		char buf[100] = { 0 };
		while (true)
		{
			cin >> buf;
			write(wfd, buf, sizeof(buf));
			bzero(buf, sizeof(buf));
		}
		close(wfd);
	}
	else if(pid >0)//父进程,只做数据接收,因此只需要读取数据即可,open的模式为只读即可
	{
		if (access("/root/projects/B2A.fifo", F_OK))//先判断文件是否存在
		{
			if (mkfifo("/root/projects/B2A.fifo", 0777) == -1)
			{
				perror("mkfifo error");
			}
			else
			{
				cout << "B2A.fifo文件创建成功" << endl;
			}
		}
		else
		{
			cout << "B2A.fifo文件已经存在" << endl;
		}
		char buf[100] = { 0 };
		int rfd = 0;
		rfd = open("/root/projects/B2A.fifo", O_RDONLY);//只读模式打开
		while (true)
		{
			
			//piepe进程读取piepe2写的数据
			int i = read(rfd, buf, sizeof(buf));//读取piepe写的数据
			if (i <= 0)
			{
				cout << "另一端已经关闭" << endl;
				close(rfd);
				return 0;
			}
			cout << "piepe读取piepe2进程写的数据:" << buf << endl;
			bzero(buf,sizeof(buf));
		}
		close(rfd);
	}
	return 0;
}

项目二:

pipe2

#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
using namespace std;
//命名管道
int main()
{
	//1.要先创建一个文件,创建特殊文件用mkfifo,不能用open创建文件
	umask(0);
	pid_t pid = 0;
	pid = fork();
	if (pid == 0)//子进程只做读取,所以open的打开模式为只读即可
	{
		if (access("/root/projects/A2B.fifo", F_OK))//先判断文件是否存在
		{
			if (mkfifo("/root/projects/A2B.fifo", 0777) == -1)
			{
				perror("mkfifo error");
			}
			else
			{
				cout << "A2B.fifo文件创建成功" << endl;
			}
		}
		else
		{
			cout << "A2B.fifo文件已经存在" << endl;
		}
		int rfd = 0;
		rfd = open("/root/projects/A2B.fifo", O_RDONLY);//只读模式打开
		char buf[100] = { 0 };
		while (true)
		{
			int i = read(rfd, buf, sizeof(buf));//读取piepe写的数据
			if (i <=0)
			{
				cout << "另一端已经关闭" << endl;
				close(rfd);
				return 0;
			}
			cout << "piepe2读取piepe进程写的数据:" << buf << endl;
			bzero(buf,sizeof(buf));
		}
		close(rfd);
	}
	else if (pid > 0)//父进程只做数据发送,只需要把数据写入到管道中即可,因此open 的文件打开类型为写入类型
	{
		if (access("/root/projects/B2A.fifo", F_OK))//先判断文件是否存在
		{
			if (mkfifo("/root/projects/B2A.fifo", 0777) == -1)
			{
				perror("mkfifo error");
			}
			else
			{
				cout << "B2A.fifo文件创建成功" << endl;
			}
		}
		else
		{
			cout << "B2A.fifo文件已经存在" << endl;
		}
		int wfd = 0;
		wfd = open("/root/projects/B2A.fifo", O_WRONLY);//写数据的模式打开
		char buf[100] = { 0 };
		while (true)
		{
			//piepe2进程写数据给piepe进程
			cin >> buf;
			write(wfd, buf, sizeof(buf));
			bzero(buf, sizeof(buf));
		}
		close(wfd);
	}
	return 0;
}

在上面的代码中可以看见我利用了

int i = read(rfd, buf, sizeof(buf));//读取piepe写的数据

            if (i <=0)

            {

                cout << "另一端已经关闭" << endl;

                close(rfd);

                return 0;

            }

这样的代码来进行一个防止管道因为一端关闭导致出现的一些问题

在双进程管道通信中,如果一端的进程突然关闭,会导致以下几种情况发生:

写端关闭:

如果写入管道的一端关闭,读取端可能会继续阻塞在读取操作上,直到读取到管道末尾的标志(EOF)为止。

如果读取端尝试从已关闭的管道中读取数据,操作系统会返回一个特殊的结束标志(通常是读取到 0 字节),表示已经读取到了管道末尾,然后读取操作会返回成功。

后续的读取操作将返回 0,指示已经读取到了管道的末尾。

读端关闭:

如果读取管道的一端关闭,写入端继续写入数据到管道中时,操作系统可能会向写入端发送一个信号(例如 SIGPIPE),告知写入端管道的另一端已经关闭。

如果写入端忽略了 SIGPIPE 信号,并继续写入数据到已关闭的管道,操作系统会将写入端的写操作视为非法操作,并且通常会导致进程收到 SIGPIPE 信号而被终止。

写入端应该处理 SIGPIPE 信号,以便在管道的另一端关闭时采取适当的措施,例如停止写入操作或进行必要的清理工作。

在任一端关闭管道时,另一端应该能够正确地处理管道关闭的情况,以确保程序能够正常运行并正确地处理管道状态。

但是其实这个操作还是有点不合理,更像是亡羊补牢,因为是已经发生了这个事情我们才去关闭另一端,因此我们在这边可以进行一个优化,就是用信号去关闭另一端进行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值