计算机系统应用教程网站

网站首页 > 技术文章 正文

Linux进程间通信——管道 linux进程间通信--管道是什么

btikc 2024-10-01 08:34:09 技术文章 11 ℃ 0 评论

管道

  • 什么是管道?
    一个进程连接到另一个进程的一个数据流称为一个“管道”。

匿名管道pipe

  • 用于父子间的通信
  • 管道最大64K,由环形队列组成
  • 需要占用两个文件描述符,分别作为管道读端、写端
  • 管道是半双工的,需要确定通信方向
    父写子读,关闭父读、子写
    子写父读,关闭子读、父写
  • 优点:稳定、经典

pipe函数原型

头文件:<unistd.h>

int pipe(int file_descriptor[2]);

功 能:创建一无名管道
参 数:file_descriptor:文件描述符数组,其中file_descriptor[0]表示读端,file_descriptor[1]表示写端
返回值:成功返回0,失败返回-1

开辟了管道之后如何实现两个进程间的通信呢?比如可以按下面的步骤通信。


1、父进程调用pipe开辟管道,得到两个文件描述符指向管道的两端。
2、父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一管道。
3、父进程关闭管道读端,子进程关闭管道写端。父进程可以往管道里写,子进程可以从
4、管道里读,管道是用环形队列实现的,数据从写端流入从读端流出,这样就实现了进程间通信。

#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) 
	{
		perror("pipe");
		exit(1);
	}
	if ((pid = fork()) < 0) 
	{
		perror("fork");
		exit(1);
	}
	if (pid > 0) // 父进程 
	{ 
		close(fd[0]);//关闭读端
		write(fd[1], "hello world\n", 12);
		wait(NULL);
	}
	else  //子进程
	{
		close(fd[1]);//关闭写端
		n = read(fd[0], line, MAXLINE);
		write(STDOUT_FILENO, line, n);
	}
	return 0;
}

运行结果

注意事项

  • 如果试图从管道写端读取数据,或者向管道读端写入数据都将导致错误发生
  • 写端未写完,写端暂时无数据,读端再次去读,read发生阻塞(读太快)
  • 读端未读完,写端满了,写端再次写,write发生阻塞(写太快)
  • 读端关闭,写端写数据,产生SIGPIPE信号,默认会终止进程
  • 写端关闭,当数据读完,再次读返回0

Linuxc/c++服务器开发高阶视频,电子书学习资料后台私信【架构】获取

有名管道fifo

pipe是有血缘关系进程之间的通信,那么当没有血缘关系的进程想要通信怎么办?

  • 创建一个有名管道fifo(也叫做named pipe),解决无血缘关系的进程通信
  • fifo是一个设备文件,本身无大小,在文件系统中以文件名的形式存在,因此即使进程与创建fifo的进程不存在血缘关系也依然可以通信,前提是可以访问该路径。
  • fifo总是遵循先进先出的原则,即第一个进来的数据会第一个被读走

与匿名管道pipe的区别

  • 提供了一个路径名与之关联,以fifo文件的形式存储于文件系统中,能够实现任何两个进程之间通信。而匿名管道对于文件系统是不可见的,它仅限于在父子进程之间的通信。 但是fifo底层是由pipe实现的。

如何创建fifo?

  • 命令行上创建
  • 程序内创建
    头文件:
    #include <sys/types.h>
    #include <sys/stat.h>
    函数原型:
    int mkfifo(const char *pathname, mode_t mode);

做个测试,分别写两个程序,一个写,一个读
写进程

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

int main(int argc, char* argv[])
{
	int fd;
	char buff[1024] = "hello world\n";

	if (argc < 2)
	{
		printf("enter you fifoname\n");
		exit(1);
	}
	fd = open(argv[1], O_WRONLY);//只写方式打开

	if (fd < 0)
	{
		perror("open\n");
	}

	write(fd, buff, strlen(buff));//写入hello world
	close(fd);

	return 0;
}

读进程

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

int main(int argc, char* argv[])
{
	int fd;
	int len;
	char buff[1024] = "hello world\n";

	if (argc < 2)
	{
		printf("enter you fifoname\n");
		exit(1);
	}
	fd = open(argv[1], O_RDONLY);//只写方式打开

	if (fd < 0)
	{
		perror("open\n");
	}

	len = read(fd, buff, sizeof(buff));
	write(STDOUT_FILENO, buff, len);
	close(fd);

	return 0;
}

测试结果如下


首先myfifo是我们提前创建好的fifo管道文件,然后执行写进程,再执行读进程。读到了hello world,执行前后myfifo文件大小都为0

注意事项

  • 当只写打开FIFO管道时,如果没有FIFO没有读端打开,则open写打开会阻塞。
  • FIFO内核实现时可以支持双向通信(pipe单向通信,因为父子进程共享同一个file结构体)
  • FIFO可以一个读端,多个写端;也可以一个写端,多个读端。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表