首页 > 系统相关 >进程间通信-信号-pipe-fifo

进程间通信-信号-pipe-fifo

时间:2022-11-07 15:03:28浏览次数:62  
标签:pipe int fifo 间通信 fd 进程 include buf

Linux进程间通信

    进程是程序运行资源分配的最小单位。每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,Inter-Process Communication)。

匿名管道pipe

    pipe只能用于有血缘关系的进程进行单向通信。调用 pipe 函数时在内核中开辟一块缓冲区(称为管道)用于通信,它有一个读端一个写端,然后通过 fd 参数传出给用户程序两个文件描述符, fd[0] 指向管道的读端, fd[1] 指向管道的写端。支持多端读或多端写,但不支持一端同时读写。也就是说,管道是半双工通信(即双方都可以发送信息,但是双方不能同时发送信息)

文件描述符

文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开的文件的记录表。当程序打开一个文件时,内核向进程返回一个文件描述符。
file descriptors: 由用户程序维护的记录表,记录的是该用户程序打开的所有的文件的fd。每个进程会预留三个默认的fd:stdin(0)、stdout(1)、stderr(2)。
file table:该表是全局唯一的,由系统内核维护,记录了所有进程打开的文件的状态、偏移量、访问模式(可读写)、文件类型、该文件对应的inode对象引用等。
Inode table: 全局唯一的表,是硬盘存储的文件的元数据的集合。

三个表的关系如下图所示:

简而言之,fd就是系统维护的file table表的某一项entry的指针,应用程序通过它能读写硬盘里文件。应用程序用它来跟内核打交道,让内核以fd定位应用程序所需访问的文件并帮忙读写数据

原文链接:

下图可以较为清楚地表明Pipe的功能:

pipe原型

#include <unistd.h>
      int pipe(int pipefd[2]);

传入的参数是一个大小为2的数组,然后就得到了两个文件描述符pipefd[0]和pipefd[1]

pipe举例

(1)举一个简单的栗子:
这里我们用一个父子进程来举例,如果要实现父子进程间的通信,在fork前就需要创建一个pipe管道

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#define MAXLINE 80
int main(void)
{
	int n;
	int fd[2];
	pid_t pid;
	char line[MAXLINE];

	if (pipe(fd) < 0)//如果管道的文件描述符小于0
	{
		perror("pipe");
		exit(1);
	}
	if ((pid = fork()) < 0)//子进程如果创建成功了,返回的pid值一定大于0
	{
		perror("fork");
		exit(1);
	}
	if (pid > 0)
	{ /* parent */
		close(fd[0]);
		write(fd[1], "hello world\n", 12);
		wait(NULL);
	}
	else
	{ /* child */
		close(fd[1]);
		n = read(fd[0], line, MAXLINE);
		write(STDOUT_FILENO, line, n);
	}
	return 0;
}

运行结果如下:

可见这是父进程把字符串“hello world”写入到管道,子进程再从管道里面读取出来并且打印到标准输出上面来。

(2)运行博客园老师所给的pipedemo.c
代码如下:

#include    <stdio.h>
#include    <stdlib.h>
#include    <string.h>
#include    <unistd.h>

int main()
{
	int	len, i, apipe[2];//两个文件描述符	
	char	buf[BUFSIZ];//长度为BUFSIZ		
	
	if ( pipe ( apipe ) == -1 ){
		perror("could not make pipe");
		exit(1);
	}
	printf("Got a pipe! It is file descriptors: { %d %d }\n", 
							apipe[0], apipe[1]);


	while ( fgets(buf, BUFSIZ, stdin) ){//从输入端获取字符,存入buf数组中
		len = strlen( buf );
		if (  write( apipe[1], buf, len) != len ){//apipe[1]是写入端,这里write()函数将buf指针指向的内存的len长个字节写入到apipe[1]所指向的管道缓冲区中。
			perror("writing to pipe");		
			break;					
		}
		for ( i = 0 ; i<len ; i++ )                     
			buf[i] = 'X' ;
		len = read( apipe[0], buf, BUFSIZ ) ;		
		if ( len == -1 ){				
			perror("reading from pipe");		
			break;
		}
		if ( write( 1, buf,len ) != len ){		
			perror("writing to stdout");		
			break;					
		}
	}
}

运行结果如下:

运行云班课里所给的代码pipedemo2.c

结果如下:

命名管道fifo

    FIFO(First In First Out)文件在磁盘上没有数据块,仅仅是内核中一条通道,各进程可以读写从而实现的进程间通信。支持多端读或多端写。
命令:mkfifo 管道名
库函数:int mkfifo(const char *pathname, mode_t mode);
我们首先需要用mkfifo myfifo生成一个fifo文件用于两个进程之间的通信

然后在同一个目录下创建两个程序文件:
wr.c:

// file: wr.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

int main()
{
	int fd, ret, i = 0;
	char buf[256];

	fd = open("myfifo", O_WRONLY);
	if(fd < 0)
	{
		perror("open error");
	}
	
	printf("write start!\n");
	while(i < 100)
	{
		snprintf(buf, 256, "hello %d\n", i);
		ret = write(fd, buf, strlen(buf));
		if(ret < 0)
		{
			perror("write error");
		}
		printf("write ok: %d\n", i);
		i++;
		sleep(1);
	}

	return 0;
}

rd.c:

// file: rd.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
	int fd, ret;
	char buf[4096];

	fd = open("myfifo", O_RDONLY);
	if(fd < 0)
	{
		perror("open error");
	}

	printf("read start!\n");
	while(1)
	{
		ret = read(fd, buf, 4096);
		write(STDOUT_FILENO, buf, ret);
		sleep(1);
	}

	return 0;
}

运行结果如下:

进入myfifo文件夹下,首先编译运行testmf.c,创建一个fifo文件,并命名为myyfifo,该文件也处在该目录下,再编译老师所给的consumer.c和producer.c代码,运行结果如下:

可见消费者端读取出了当时在生产者端写入的hahahah,fifo管道建立成功。

标签:pipe,int,fifo,间通信,fd,进程,include,buf
From: https://www.cnblogs.com/ssssspm/p/16863574.html

相关文章

  • Jenkins Pipeline SSH Publisher 环境变量、参数引用 要用双引号
    JenkinsPipelineSSHPublisher环境变量、参数引用 要用双引号在Pipeline 脚本中,如果要使用变量,就必须使用“ 双引号pipeline{agentanyenvironment......
  • 可编程渲染管线(Scriptable Render Pipeline, SRP)
    原文链接可编程渲染管线处理数据的流程可分为以下3大阶段1.应用阶段这个阶段大概会由CPU处理4件事情。首先会对模型数据进行可见性判断。模型数据由顶点位置、法线方......
  • vue3使用mitt 实现组件之间通信 (不限制组件之间关系)
    安装mittyarnadd-savemittnpminstallmitt创建miit示例mitt.tsimportmittfrom'mitt'exportdefaultmitt()组件A中引入mitt并使用emit发送数......
  • 进程间通信
    进程通信的目的数据传输:一个进程需要将它的数据发送给另一个进程资源共享:多个进程之间共享同样的资源。通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)......
  • JavaScript中的Pipe
    JavaScript中的Pipe本文会介绍Pipe在函数式编程中的基本概念,怎么用Pipe让我们的代码变得更美好,以及新的pipe操作符,Fancy的东西在后面!什么是Pipe?先用一个最简单的例子来看......
  • pipeline 流程
    Pipeline提交、测试、部署流程一、提交阶段:1.更新代码2.构建3.单元测试4.质量扫描node{gitlabCommitStatus(builds:["CommitBuild"]){stage('CodePUll')......
  • VideoPipe可视化视频结构化框架新增功能详解(2022-11-4)
    VideoPipe从国庆节上线源代码到现在经历过了一个月时间,期间吸引了若干小伙伴的参与,现将本阶段新增内容总结如下,有兴趣的朋友可以加微信拉群交流。项目地址:https://github.......
  • Jenkins Pipeline 多分支流水线 Input length = 1
    Jenkins多分支流水线构建过程中报错。[Pipeline]//node[Pipeline]EndofPipelinejava.nio.charset.MalformedInputException:Inputlength=1 atjava.base/ja......
  • JS中的pipe原理
    学习reduce()时遇到一个练习“功能型函数管道”,对于代码中的pipe不能理解,类似于下面这一行代码,信息量很丰富,有es6中的扩展运算符,箭头函数,reduce()方法。constpipe=(........
  • Jenkins 如何配置流水线pipeline?
    1.新建任务--选择流水线风格     2.勾选不允许并发执行(根据需要,我需要它按顺序执行)    3.写流水线命令3.1勾选helloworld模板 4.查看流水线语......