首页 > 系统相关 >进程-管道

进程-管道

时间:2024-09-21 18:50:22浏览次数:13  
标签:OK int fifo mkfifo 管道 进程

管道定义

        什么是管道

                管道是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

相关文章

  • 进程控制
    fork()执行完之后,返回值为什么父进程和子进程的pid变量会不同返回值?当fork()被调用时,操作系统会创建一个与父进程几乎相同的子进程,子进程会从fork()返回的位置开始执行。在子进程中,fork()返回值为0,表示它是新创建的进程。在父进程中,fork()返回子进程的PID,表示它是父......
  • Linux:进程(三)
    目录Linux源代码对进程的描述RSDTtXZ(进程僵尸)孤儿进程Linux源代码对进程的描述    理论上把进程状态大致被分为了:运行、阻塞、挂起。那么,在操作系统中具体是如何描述状态的。(有时候Linux内核也把进程称为任务)    Linux内核的源代码定义:/**The......
  • Linux中的进程信号
    在Linux系统中,信号是一种用于进程间通信和进程控制的机制,它允许系统内核和用户进程对其他进程进行通知、干预和控制。信号可以被用于各种用途,例如终止进程、暂停进程、捕捉异常以及处理用户自定义事件。为了更好地理解进程信号,我们将从以下几个方面进行探讨:信号的基本概念:什么是......
  • 光学式管道液体传感器LL10AH05 拖把洗地机清水箱与污水箱专用检测传感器
    应用领域:拖把洗地机咖啡机净水器饮水机管道水流检测 产品特征:无机械运动部件、可靠性高体积小、成本低液位控制精度高防水等级 IP66......
  • 进程的状态
    目录进程的状态从操作系统的角度宏观的看待进程状态:S:T:R/R+D进程的状态pid_tid=fork();if(id<0){perror("fork");return1;}elseif(id==0){//childwhile(1){printf("Sonp......
  • oracle常用后台进程及sql语句执行流程
    1.checkpoint功能:减少崩溃恢复crashrecovery时间。检查点可以确保在某个时间点之前的所有事务都写入磁盘,保证数据一致性后台进程ckpt触发,ckpt通知dbwr进程将脏数据库dirtybuffer写出到数据文件上.更新数据文件头及控制文件上的检查点触发条件:数据库一致性关闭、altersystem......
  • linux 基础知识 什么是僵尸进程?有什么影响?如何解决?
    linux系统僵尸进程在Linux系统中,僵尸进程(ZombieProcess)是一种特殊的进程状态,它指的是一个已经完成执行的进程,其父进程尚未通过wait()或waitpid()系统调用来回收其资源和状态信息。僵尸进程本身并不占用CPU和其他资源,但它的进程描述符(PCB)仍然保留在系统中,这会占用系统资源并可......
  • 进程
    1.c语言和cpp语言中,这个不是内存,%p进程认为自己是独占空间的,实际上不是这样子的。pcb中存了一个内存空间,进程地址空间页表是进程内存管理的核心部分,它管理了进程虚拟内存到物理内存的映射关系。通过页表,操作系统可以为每个进程提供独立的虚拟地址空间,并实现内存分页......
  • 进程间通信-信号
    大部分信号是异步的/*1-31号信号 非实时信号(所有非实时信号优先级相同) ---不可靠信号不可靠:处于就绪队列多个相同的非实时信号只会被响应一次,其余的被丢弃特征:1、不排队,会相互嵌套(例如家里来客人1先来,招待1的过程中2来了就立马去招待2)2、处于就绪队列多个相同的非实时......
  • 11 UML中的逻辑视图、进程视图、实现视图、部署视图
    UML(UnifiedModelingLanguage,统一建模语言)是一种用于对软件密集系统进行可视化建模的标准语言。在UML中,系统可以从不同的角度进行描述,这些不同的角度被称为视图。具体来说,UML中的逻辑视图、进程视图、实现视图和部署视图分别代表了系统的不同方面。1.逻辑视图(LogicalView)定义......