【Linux】进程间通信(管道)

(一)管道

管道可以在两个进程间传递数据,比如ls -l | grep main.c,其中的"|"就是管道。
上述命令的意思就是查看当前所在目录的结果写入管道,然后grep再从管道中过滤得到main.c的文件显示在屏幕上;

(二)管道的分类

(1)有名管道

  1. 创建方式
  • 命令创建 mkfifo FIFO
  • 系统调用创建int mkfifo(const char* filename, mode_t mode);
    头文件(sys/types.h sys/stat.h)
  1. 进程a从键盘获取数据,通过管道发送给进程b进行输出

a.c

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
void Send()
{
    
    
	int fd = open("FIFO", O_WRONLY);
	if(fd == -1) return;
	printf("input data:");
	while(1)
	{
    
    
		char buff[128] = {
    
    0};
		fgets(buff, 127, stdin);

		if(strncmp(buff, "end", 3) == 0)
		{
    
    
			break;
		}

		write(fd, buff, strlen(buff) - 1);

	}
	close(fd);
}
int main()
{
    
    
	Send();
	
	return 0;
}

b.c

#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
void Recv()
{
    
    
	int fd = open("FIFO", O_RDONLY);
	if(fd == -1) return;
	printf("reading data...\n");

	while(1)
	{
    
    
		char buff[128] = {
    
    0};
		int ret = read(fd, buff, 127);
		if(ret <= 0)
			break;

		if(strncmp(buff, "end", 3) == 0)
		{
    
    
			break;
		}
		printf("%s\n", buff);
	}
	close(fd);
}
int main()
{
    
    
	Recv();
	return 0;
}
  • 结果:
    在这里插入图片描述

(2)无名管道

  1. 无名管道主要用于父子进程间通信

  2. 创建方式:

  • 头文件 unistd.h
  • 系统调用int pipe(int pipefd[2]);
  • pipe()返回值:成功0,失败-1
  • fd[0]管道读端
  • fd[1]管道写端
  1. 代码
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
void fun(int sig)
{
    
    
	int status;
	while(waitpid(-1, &status, WNOHANG) > 0);
}

void DataTransmission()
{
    
    
	int fd[2];
	int ret =  pipe(fd);
	if(ret == -1)
	{
    
    
		printf("pipe err\n");
		return;
	}
	//注册SIGCHLD信号应答
	signal(SIGCHLD, fun);

	pid_t pid = fork();
	if(pid == -1)
	{
    
    
		printf("fork err\n");
		return;
	}

	if(pid == 0)
	{
    
    
		//子进程当作写端
		close(fd[0]);
		while(1)
		{
    
    
			printf("child input data:\n");
			char buff[128] = {
    
    0};
			fgets(buff, 127, stdin);

			if(strncmp(buff, "end", 3) == 0)
			{
    
    
				break;
			}
			write(fd[1], buff, strlen(buff) - 1);
		}

		//关闭写端
		close(fd[1]);

		//退出子进程,自动向父进程发送SIGCHLD信号
		exit(0);
	}
	//父进程
	else
	{
    
    	
		//关闭写端
		close(fd[1]);
		
		while(1)
		{
    
    
			char buff[128] = {
    
    0};
			int ret = read(fd[0], buff, 127);
			if(ret <= 0)
				return;
			if(strncmp(buff, "end", 3) == 0)
				break;
			printf("father read data:%s\n", buff);
		}
		close(fd[0]);
	}
}
int main()
{
    
    
	DataTransmission();
	return 0;
}
  • 结果:
    在这里插入图片描述

(3)管道的特点

  • 有名管道、无名管道写入管道的数据都存放在内存中
  • 管道是一种半双工通信方式(通信方式有单工、半双工、全双工)
  • 有名管道与无名管道区别:有名管道可以在任意进程间使用,而无名管道在父子进程间通信。

(4)管道的实现

在这里插入图片描述

Guess you like

Origin blog.csdn.net/xiaoxiaoguailou/article/details/121509942