Linux 进程间通信 一、管道

进程间通信

进程之间无法直接通信,因为每个进程都有自己的独立的虚拟地址空间,访问的都是自己的虚拟地址。如果将一号进程的虚拟地址传给二号进程,通过二号进程的页表来映射,并不能映射到正确的物理地址空间。所以两个进程的映射关系并不同,具有独立性,因此无法直接通信。

进程间通信的原理:操作系统为进程间提供一个公共的传输媒介,实现公共访问,进而实现进程间通信。

操作系统根据需求不同提供了不同的进程间通信的方式:

  • 管道
  • 共享内存
  • 消息队列
  • 信号量

管道

特性:半双工通信,就是可以选择方向的单向通信。
本质:系统内核中的一块儿缓冲区(内核空间中开辟的一块儿内存)。
通信原理:多个进程只要能够访问同一块儿内核中的缓冲区(管道)就能实现通信。
分类:

  • 匿名管道:只能用于具有亲缘关系的进程间通信。
  • 命名管道:可以用于同一主机上任意进程间通信。
匿名管道

管道缓冲区没有标识符,无法被其他的进程找到,因此只能通过子进程复制父进程的方式获得到管道的操作句柄,进行通信。

int pipe(int pipefd[2]);

  • pipefd[0]:用于从管道里读取数据。
  • pipefd[1]:用于将数据写入管道中。
  • 返回值:成功返回0,失败返回-1。

通过IO操作完成对管道的操作。

代码操作:

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

int main ()
{
	int pipefd[2];
	int ret = pipe(pipefd);
	if(ret < 0)
	{
		perror("pipe error");
		return -1;
	}

	pid_t pid = fork();
	if(pid < 0)
	{
		perror("fork error");
		exit(-1);
	}
	else if (pid == 0)
	{
		//子进程
		char buf[1024] = {0};
		int ret = read(pipefd[0], buf, 1023);
		if (ret < 0)
		{
			perror("read error");
			return -1;
		} 
		prinff("buf:%s",buf);
	}
	else
	{
		//父进程
		char* ptr = "hello world\n";
		int ret = write(pipefd[1], ptr, strlen(ptr));
		if (ret < 0)
		{
			perror("write error");
			return -1;
		}
		porintf("写入成功\n");
	}
	return 0;
}

在这里插入图片描述
我们知道,父子进程先运行哪个并不一定,如果先运行了子进程,也就是先从管道读取了数据,但是此时父进程并没有向管道中写入数据,那我们能读取到数据吗?

管道的读写特性:

  • 若管道中没有数据,read会阻塞; 若管道中数据写满了,write回阻塞
  • 若管道的所有读端被关闭,则继续write就会触发异常,导致进程退出。
  • 若管道的所有写端被关闭,read读完所有数据后,则不在阻塞,返回0.
命名管道

管道缓冲区具有标识符,所以可以用于同一主机上任意进程间通信。

命名操作:mkfifo+文件名;创建一个管道文件。

命名管道的本质依然是内核中的一块儿缓冲区,但是命名管道具有名字,具有标识符,而这个标识符就是一个可见于文件系统的管道类型文件。多个进程可以打开同一个管道文件,访问同一块内核中的缓冲区,实现通信。

int mkfifo(const char *pathname, mode_t mode);
代码操作:
1.fifo_read.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcnlt.h>
#include <sys/stat.h>

int main ()
{
	umask(0);
	char* fifo_name = "./test.fifo";
	int ret = mkfifo(fifo_name, 0664);
	if (ret < 0)
	{
		perror("mkfifo error");
		return -1;
	}
	int fd = open(fifo_name,O_RDONLY);
	if (fd < 0)
	{
		perror("open error");
		return -1;
	}
	printf("open fifo success\n");

	while(1)
	{
		char buf[1024] = {0};
		int ret = read(fd, buf, 1023);
		if (ret < 0)
		{
			perror("read error");
			return -1
		}
		else if (ret == 0)
		{
			printf("all write closed\n");
			return -1;
		}
		printf("buf:%s",buf);
	}
	close(fd);
	return 0;
}

2.fifo_write.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcnlt.h>
#include <sys/stat.h>

int main ()
{
	umask(0);
	char* fifo_name = "./test.fifo";
	int ret = mkfifo(fifo_name, 0664);
	if (ret < 0 && errno != EEXIST)
	{
		perror("mkfifo error");
		return -1;
	}
	int fd = open(fifo_name,O_WRONLY);
	if (fd < 0)
	{
		perror("open error");
		return -1;
	}
	while(1)
	{
		char buf[1024] = {0};
		scanf("%s",buf);
		int ret = write(fd, buf, strlen(buf));
		if (ret < 0)
		{
			perror("write error");
			return -1
		}
	}
	close(fd);
	return 0;
}

在这里插入图片描述
在这里插入图片描述
总结管道的特性:
1.半双工通信:可以选择方向的单向通信。
2.管道提供字节流传输服务:有序的、基于连接的、可靠的传输方式。

  • 基于连接的:所有读端被关闭,则write触发异常;所有写端被关闭,则read读完数据后返回0,不再阻塞。

3.管道自带同步与互斥:

  • 同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。
  • 互斥:通过保证同一时间对临界资源的唯一访问保证操作安全性。

4.管道的生命周期随进程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值