Linux----进程间通信-管道与两个命名管道实现进程双向通信

在Linux系统中,有时候需要多个进程之间相互协作,共同完成某项任务,进程之间或线程之间有时候需要传递信息,有时候需要同步协调彼此工作,则就会出现进程间通信(interprocess communication 或者 IPC)

信号也是进程间通信的一种机制,尽管其主要作用不是这个,一个进程向另一个进程发送信号,传递的信息是信号编号,当采用sigqueue()函数发送信号时,还可以在信号上绑定数据(整型数字或指针),增强传递消息的能力,尽管如此,还是不建议将信号作为进程间通信的常规手段

//进程间的通信手段:
1、通信类:主要是在进程之间传递消息(消息队列),交换数据(通过共享一块内存来完成信息的交换)
2、同步类:协调进程间的操作,某些操作,多个进程间不能同时执行,需要借助一些同步类工具

匿名管道:

第一个广泛应用的进程间通信手段,日常在终端执行shall命令时,会大量使用管道,管道会被有血缘关系的进程共享,相当于创建了一个家庭公共场所(临界资源),每个家庭成员可以将信息(临界区)存放在里面,等待另一个成员来取走信息,阅后即焚,(读取管道的内容是消耗性的,读了之后就不会再管道中出现),任何时候家庭公共场所只能有一个成员去访问临界资源,访问期间支持原子性(对临界资源的操作成功或操作失败)

管道的实质:
内核维护了一块与管道文件相关联的缓冲区,对管道文件的操作,被内核转化成对这块缓冲区的操作

缺陷: 只能用于有血缘关系的进程之间,例如父子进程之间

#include<unistd.h>
int pipe(pipefd[2]);
pipefd[2]//用来返回文件描述符的数组
pipefd[0]//为读打开,为读端
pipefd[1]//为写打开,为写端
//通常调用pipe()之后会调用fork进行创建父子进程,进行通信,对于管道数据的流向,要么父进程(写,关闭读端),子进程(读,关闭写端),要么子进程(写,关闭读端),父进程(读,关闭写端),在此之间,双方可以调用read(对于读进程)和write(对于写进程)对未关闭的文件描述符进行读写操作

//读写规则
1、读一个写端关闭的管道,在所有数据读完之后,read返回0,以指示文件到结尾处

2、如果写一个读端已关闭的管道,则产生SIGPIPE信号,捕捉信号write出错返回

3、互斥与原子性,在写的时候,读端不允许访问管道,并且已写尚未读取的字节数应该小于或等于PIPE_BUF(一般为4096字节)所规定的缓存大小

//当所有的读端与写端全部关闭后,管道才能被销毁

这里写图片描述
管道一般情况下单向通信,否则会出现内容混乱,可以建立两个管道支持双向通信

#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
	int pipefd[2];//创建之后返回两个文件描述符pipefd[0]--读端    pipefd[2]--写端
	pid_t cpid;
	char buf;
	
	if (pipe(pipefd) == -1)//创建管道
	{
		perror("pipe");
		exit(EXIT_FAILURE);
	}
	cpid = fork();//创建子进程
	if (cpid<0)
	{
		perror("fork cpid error");
		exit(EXIT_FAILURE);
	}

	if (cpid == 0)//child
	{
		close(pipefd[0]);//关闭文件描述符0,读端 
		int i = 0;
		char* _mesg = NULL;
		while (i<20)
		{
			_mesg = "hello father !  i am  child.\n ";
			write(pipefd[1], _mesg, strlen(_mesg)+1);
			sleep(1);
			i++;
		}
	}
	else//father
	{
		close(pipefd[1]);//父进程将argv[1]写入管道,关闭读端 
		char _mesg_f[100];
		int j = 0;
		while (j < 20)
		{
			memset(_mesg_f, '\0', sizeof(_mesg_f));
			read(pipefd[0], _mesg_f, sizeof(_mesg_f));
			sleep(3);
			printf("%s\n", _mesg_f);
			j++;
		}

	}
	return 0;
}


管道内存区大小:

1、管道本质是一片内存区域,自然有大小,管道默认大小为65536字节(2的16次方),是内核内存中的一个缓冲区,可以用fcntl来获取和修改这个值得大小

pipe_capacity = fcntl(fd,?F_GETPIPE_SZ)
//获取管道大小

ret  = fcntl(fd,?F_SETPIPE_SZ,size);
//设置管道大小

管道内存大小必须设置在页面大小和上限值之间
管道有大小,写入应该慎重,不能连续的写入大量数据,一旦管道填满,写入就会阻塞,对于读端,要及时读取数据,防止管道被写满,造成写入阻塞。

2、 pipe_buf .定义的是内核管道缓冲区的大小,这个值的大小是由内核设定的,这个值仅需一条命令就可以查到;而pipe capacity指的是管道的最大值,即容量,是内核内存中的一个缓冲区

命名管道FIFO:

为了解决无名管道而引入的,与匿名管道类似,最大的区别是,有实体文件与之关联,由于存在实体文件,不相关的没有血缘关系的进程也可以相互通信


#include<sys/types.h>
#include<sys/stst.h>
int mkfifo(const char* pathname,mode_t mode)
pathname  //要创建的或打开的文件名
mode  // 存取访问限权

//命令创建:mkfifo [-m mode] pathname(创建命名管道的文件名)
//        mknod [-m mode] pathname p(p表示要创建命名管道)
从外表看,我是一个FIFO 文件,有文件名,任何进程都可以打开
从核心看,与匿名管道一模一样,

if(mkfifo("/temp/fifo",S_IFIFO|0666) == -1)//尽量使用
{
   perror("mkfifo error");
   exit(1);
}
if(mknod("/temp/fifo",S_IFIFO|0666) == -1)
{
   perror("mkfifo error");
   exit(1);
}

//S_IFIFO | 0666    指明了创建一个命名管道的权限

用两个命名管道实现进程实现双向通信

代码如下:
这里写图片描述

这里写图片描述

这里写图片描述

  • 8
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值