进程间的通信

本文详细介绍了Linux中的进程间通信方式,特别是无名管道和有名管道的特点、创建方法以及它们在半双工和全双工通信中的作用。通过实例演示了如何使用无名管道进行进程通信,并探讨了有名管道的创建、使用和注意事项。
摘要由CSDN通过智能技术生成

🛑进程间的通信

在这里插入图片描述
UNIX平台进程通信方式

  • 早期进程间通信方式
  • AT&T的贝尔实验室,对Unix早期的进程间通信进行了改进和扩充,形成了“system V IPC”,其通信进程主要局限在单个计算机内
  • BSD(加州大学伯克利分校的伯克利软件发布中心),跳过了该限制,形成了基于套接字(socket)的进程间通信机制

Linux继承了上述所有的通信方式

🍃Linux通信方式

早期进程间通信方式:无名管道、有名管道、信号

🌿无名管道

🍀特点

只能用于具有亲缘关系的进程之间的通信 半双工的通信模式,具有固定的读端和写端

  • 单工通信:固定的读端和写端,方向不可更改
  • 半双工:两者都能发或者收,但是在同一时间内,只能有一个方向
  • 全双工:两者都能发收,而且可以同时进行

管道可以看成是一种特殊的文件,对于它的读写可以使用文件IO如read、write函数。

管道是基于文件描述符的通信方式。当一个管道建立时,它会创建两个文件描述符fd[0]和fd[1]。其中fd[0]固定用于读管道,而fd[1]固定用于写管道。
构成了一个半双工的通道。

在这里插入图片描述

🍀创建管道

头文件:
#include <unistd.h>

函数原型:
int pipe(int fd[2])

函数参数:
fd:包含两个元素的整型数组

函数返回值:
成功:0
失败:-1

在这里插入图片描述

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>

int main(int argc, const char *argv[])
{
	int fd[2] = {0}; //fd[0] 读 fd[1] 写
	//通过pipe创建无名管道
	if(-1 == pipe(fd)) //pipe(fd[2]);
	{
		perror("pipe");
		return -1;
	}
	puts("pipe OK!");
	//创建进程
	//子进程往父进程发送数据
	pid_t pid = 0;
	pid = fork();
	if(pid < 0)
	{
		perror("fork");
		return -1;
	}
	if(pid == 0) //子进程
	{
		//1、关闭读端
		close(fd[0]);
		char buf[20] = {0};
		//输入数据
		printf("write %d :", getpid());
		fgets(buf, sizeof(buf), stdin);
		//将数据写入到管道中
		write(fd[1], buf, strlen(buf));
		//关闭写段
		close(fd[1]);
	}
	if(pid > 0) //父进程
	{
		//1、关闭写端
		close(fd[1]);
		//从管道读数据
		char buf[20] = {0};
		read(fd[0], buf, sizeof(buf));
		printf("read %d :%s", getpid(), buf);
		//关闭读端
		close(fd[0]);
	}
	return 0;
}

在这里插入图片描述
在这里插入图片描述

🍀探究无名管道有多大?

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <sys/wait.h>
#include <stdlib.h>

int main(int argc, const char *argv[])
{
	char buf[1024] = {0};
	int fd[2] = {0}; //fd[0] 读 fd[1] 写
	//通过pipe创建无名管道
	if(-1 == pipe(fd)) //pipe(fd[2]);
	{
		perror("pipe");
		return -1;
	}
	puts("pipe OK!");
	int count = 0;
	while(1)
	{
		write(fd[1], buf, sizeof(buf));
		count++;
		printf("%dK\n", count);
	}
	return 0;
}

在这里插入图片描述

🍀注意

在这里插入图片描述

🌿有名管道

在这里插入图片描述
创建有名管道:计算机会在内核空间上创建有名管道并且在用户空间上虚拟出来一个文件,该文件能访问到管道mkfifo

🍀特点

  • 无名管道只能用于具有亲缘关系的进程之间,这就限制了无名管道的使用范围
  • 有名管道可以使互不相关的两个进程互相通信。有名管道可以通过路径名来指出,并且在文件系统中可见
  • 进程通过文件IO来操作有名管道
  • 有名管道遵循先进先出规则
  • 不支持如lseek() 操作

🍀创建有名管道

头文件:
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>

函数原型:
int mkfifo(const char *filename, mode_t mode)

函数参数:
filename:要创建的管道
mode:指定创建的管道的访问权限,一般用8进制数表示

函数返回值:
成功:0
失败:-1

返回值错误
EACCESS参数filename所指定的目录路径无可执行权限
EEXIST参数filename所指定的文件已存在
ENAMETOO LONG参数filename的路径名称太长
ENOENT参数filename包含的目录不存在
ENOSPC文件的剩余空间不足
EROFS参数filename指定的文件存在于只读文件系统内
#include "./myhead.h"
#include <fcntl.h>
#include <errno.h>

int main(int argc, const char *argv[])
{
	int fd = 0;
	char buf[20] = {0};
	//创建又名管道
	//mkfifo(char *pathname, mode);
	if(-1 == mkfifo("myfifo", 0666) && errno != EEXIST)
	{
		perror("mkfifo");
		return -1;
	}
	//往又名管道中写入数据
	//打开文件
	fd = open("myfifo", O_WRONLY);
	if(fd < 0)
	{
		perror("open");
		return -1;
	}
	//往文件中写
	while(1)
	{
		memset(buf, 0, sizeof(buf));
		printf("write:\n");
		fgets(buf, sizeof(buf), stdin);
		//把数据写入到管道文件中
		write(fd, buf, strlen(buf));
		if(strncmp(buf, "quit", 4) == 0)
		{
			break;
		}
	}
	close(fd);
	return 0;
}

在这里插入图片描述

#include "./myhead.h"
#include <fcntl.h>
#include <errno.h>

int main(int argc, const char *argv[])
{
	int fd = 0;
	char buf[20] = {0};
	//创建又名管道
	//mkfifo(char *pathname, mode);
	if(-1 == mkfifo("myfifo", 0666) && errno != EEXIST)
	{
		perror("mkfifo");
		return -1;
	}
	//从又名管道中读数据
	//打开文件
	fd = open("myfifo", O_RDONLY);
	if(fd < 0)
	{
		perror("open");
		return -1;
	}
	//从文件中读
	while(1)
	{
		memset(buf, 0, sizeof(buf));
		read(fd, buf, sizeof(buf));
		printf("read:%s", buf);
		if(strncmp(buf, "quit", 4) == 0)
		{
			break;
		}
	}
	close(fd);
	return 0;
}

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值