Linux系统应用编程---进程间通信(pipe、FIFO)

      每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。

 

一、pipe管道(无名管道)

#include <unistd.h>

int pipe(int filedes[2]);
  1. 管道作用于有血缘关系的进程之间,通过fork来传递
  2. 调用pipe函数时在内核中开辟一块缓冲区(称为管道)用于通信,它有一个读端一个写端,然后通过filedes参数传出给用户程序两个文件描述符,filedes[0]固定用于管道的读端,filedes[1]固定用于管道的写端(很好记,就像0是标准输入1是标准输出一样)。所以管道在用户程序看起来就像一个打开的文件,通过read(filedes[0]);或者write(filedes[1]);向这个文件读写数据其实是在读写内核缓冲区。
  3. pipe函数调用成功返回0,调用失败返回-1。
  4. 无名管道是单工的工作方式,即同一时刻要么只能读管道,要么只能写管道。父子进程虽然同时拥有管道的读端和写端,但只能使用其中一个。

程序1:实现父进程写,子进程读父进程写的内容,并将读到的内容输出到标准输出。

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

int main(void)
{
	int fd[2];
	char str[1024] = "hello world.\n";
	char buf[1024];
	pid_t pid;
	
	//fd[0]读端, fd[1]写端
	if(pipe(fd) < 0){
		perror("pipe");
		exit(1);
	}
	
	pid = fork();
	//父写子读
	if(pid > 0){		//父进程
		close(fd[0]);	//关闭父进程的读端
		sleep(2);
		write(fd[1], str, strlen(str));
		wait(NULL);
	}
	else if(pid == 0){//子进程
		int len;
		close(fd[1]);	//关闭子进程的写端
		len = read(fd[0], buf, sizeof(buf));
		//sprintf(str, "child %s", buf);
		write(STDOUT_FILENO, buf, len);		//将子进程读到的内容输出到标准输出
	}
	else{
		perror("fork");
		exit(1);
	}
	
	return 0;	
}

使用pipe管道时要注意:

1、写管道关闭,读端读完管道里面内容时,再次读,返回0,相当于读到EOF

2、写端未关闭,写端暂时无数据;读端读完管道里数据时,再次读,阻塞

3、读端关闭,写端写管道,产生SIGPIPE信号,写进程默认情况下回终止进程

4、读端为读管道数据,当写端写满管道数据后,再次写,阻塞

 

二、FIFO有名管道

通过mkfifo指令创建管道文件(注意在WinShare目录下不能创建管道文件,因为windows没有管道文件)

fifo_write.c----向管道文件中写数据

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

void sys_err(char *str, int exitno)
{
	perror(str);
	exit(exitno);
}

int main(int argc, char * argv[])
{
	int fd;
	char buf[1024] = "hello world.\n";
	if(argc < 2){
		printf("./a.out fifoname.\n");
		exit(1);
	}
	
	//fd = open(argv[1], O_RDONLY);
	fd = open(argv[1], O_WRONLY);

	if(fd < 0)
		sys_err("open", 1);
	
	write(fd, buf, strlen(buf));
	close(fd);
	
	return 0;	
}

 

fifo_read.c---读取管道文件中的数据

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

void sys_err(char *str, int exitno)
{
	perror(str);
	exit(exitno);
}

int main(int argc, char *argv[])
{
	int fd, len;
	char buf[1024];
	if(argc < 2){
		printf("./a.out fifoname.\n");
		exit(1);
	}
	
	//fd = open(argv[1], O_RDONLY);
	fd = open(argv[1], O_RDONLY);
	if(fd < 0)
		sys_err("open", 1);
	
	len = read(fd, buf, sizeof(buf));
	write(STDOUT_FILENO, buf, len);
	close(fd);
	
	return 0;
	
}

执行的时候开两个终端窗口,先执行fifo_write.c,向管道中写数据,可以看到此时是阻塞的;

打开另外一个终端窗口,执行fifo_read.c,可以看到读出管道的数据,并打印在终端。

同时可以看到读写前后管道文件的大小是不变的

猜你喜欢

转载自blog.csdn.net/weixin_42445727/article/details/89034469