系统编程第二节——管道

2021/7/21 1:05:58

本文主要是介绍系统编程第二节——管道,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Linux进程间通信

1、进程间通信的类型

  1. 管道(pipe)和命名管道(FIFO)
  2. 信号(signal)
  3. 共享内存
  4. 消息队列
  5. 信号量
  6. 套接字

2、管道

  管道是Linux中最常用的进程间通信 IPC 机制。使用管道时,一个进程的输出可以成为另外一个进程的输入。
  当输入/输出的数据量特别大时,管道的这种 IPC 机制就非常有用。
  在Linux中,通过将两个file结构指向同一个临时的VFS节点,这个VFS节点又指向同一个物理页而实现管道。

3、pipe管道

若要创建一个简单的管道,可以使用系统调用pipe(),它接受一个参数,也就是一个包括两个整数的数组。如果系统调用成功,此数组将包括管道使用的两个文件描述符,一个为读端,一个为写端。pipe管道是半双工的,数据只能向一个方向流动,需要双方通信时,就建立两个管道。pipe管道只能用于父子进程或者兄弟进程之间。

头文件: #include <unistd.h>

函数原型: int pipe( int filedes[2])
filedes: 管道文件描述符,当为0时,pipe端代码工程为读端;当为1时,pipe端代码工程为写端;
filedes[0]: 管道的读端
filedes[1]: 管道的写端
函数返回值:成功为 0 ;错误为 1

#include <stdio.h>
#include <unistd.h>
#include <string.h>
/*父子进程通过无名管道进行通信*/
int main(int argc, char *argv[])
{
	//1, 创建无名管道
	int fd[2];
	char buf[64];	
	
	int ret = pipe(fd);
	if(-1 == ret)
	{
		perror("pipe failed");
		return -1;
	}
	
	//2, 创建子进程
	pid_t pid = fork();
	if(-1 == pid)
	{
		perror("fork faied");
		return -1;
	}
	//3, 父进程循环从键盘获取数据写入无名管道 --> 写入端 fd[1]
	if(pid > 0)
	{
		while(1)
		{
			memset(buf, 0, sizeof(buf));
			fgets(buf, sizeof(buf), stdin);	
			write(fd[1], buf, sizeof(buf));
		}
	}
	//4, 子进程循环从无名管道中读取数据
	if(0 == pid)
	{
		while(1)
		{
			memset(buf, 0, sizeof(buf));
			read(fd[0], buf, sizeof(buf));	//默认是阻塞的
			printf("readbuf:%s", buf);
		}
	}
	
	return 0;
}


4、命名管道

命名管道与一般管道要一些不同点
1) 命名管道是在文件系统中作为一个特殊的设备文件而存在的。
2) 不同管道的进程之间可以通过命名管道共享数据。
3) 当共享命名管道的进程执行完所有的 I/O 操作后,命名管道将继续保存在文件系统中,以便以后使用。
4) 普通管道只能由父子兄弟相关进程使用,它共同的祖先进程创建了管道。但是,通过命名管道,不相关的进程也能交换数据。
5) 一旦用mkfifo函数创建了一个命名管道,就可以 open 打开它。一般的文件 I/O 函数( close , read , write , unlink )都可用于命名管道。

函数头文件:
#include <sys/types.h>
#include <sys/stat.h>
函数原型:
int mkfifo(const char * pathname,mode mode)
pathname: 管道文件名
mode: 管道创建方式
函数返回值:
成功: 0
失败: -1

代码例程:

读端代码

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

#define  FIFO_PATH  "/home/gec/myfifo"
/*有名管道读端程序*/
int main(int argc, char *argv[])
{
	//1, 判断有名管道是否存在 --> 不存在则创建
	if( access(FIFO_PATH, F_OK) != 0)	//access返回值不等于0,表示文件不存在
	{
		int ret = mkfifo(FIFO_PATH, 0777);
		if(-1 == ret)
		{
			perror("mkfifo failed");
			return -1;
		}
	}
	
	//2, 直接打开有名管道 --> open()
	int fd = open(FIFO_PATH, O_RDWR);
	if(-1 == fd)
	{
		perror("open failed");
		return -1;
	}
	
	//3, 循环获取读取管道中数据	--> "EXIT\n"
	char buf[128];
	while(1)
	{
		memset(buf, 0, sizeof(buf));
		read(fd, buf, sizeof(buf));
		if( strcmp("EXIT\n", buf) == 0 )
			break;
		printf("readbuf:%s", buf);
	}
	//4, 关闭管道文件
	close(fd);	
	return 0;
}

写端代码

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

#define  FIFO_PATH  "/home/gec/myfifo"

/*有名管道写端程序*/
int main(int argc, char *argv[])
{
	//1, 判断有名管道是否存在 --> 不存在则创建
	if( access(FIFO_PATH, F_OK) != 0)	//access返回值不等于0,表示文件不存在
	{
		int ret = mkfifo(FIFO_PATH, 0777);
		if(-1 == ret)
		{
			perror("mkfifo failed");
			return -1;
		}
	}
	
	//2, 直接打开有名管道 --> open()
	int fd = open(FIFO_PATH, O_RDWR);
	if(-1 == fd)
	{
		perror("open failed");
		return -1;
	}
	
	//3, 循环获取数据写入管道
	char buf[128];
	while(1)
	{
		memset(buf, 0, sizeof(buf));
		fgets(buf, sizeof(buf), stdin);
		write(fd, buf, sizeof(buf));
		if( strcmp("EXIT\n", buf) == 0 )
			break;
	}
	//4, 关闭管道文件
	close(fd);
	
	return 0;
}





这篇关于系统编程第二节——管道的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程