进程间通信,有名管道(pipe)与无名管道(fifo)的解析与运用,以及代码实现

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

 

 【进程通信与并发】专题正在持续更新中进程线程IPC线程池等的创建原理与运用✨欢迎大家前往订阅本专题获取更多详细信息哦

本系列专栏 -  进程通信与并发

欢迎大家    点赞  评论  收藏⭐️

个人主页 - 勾栏听曲_0的博客

希望本文能对你有所帮助如有不足请指正共同进步吧

善治病者必医其受病之处善救弊者必塞其起弊之源。

无名管道pipe

介绍

        它在文件系统中没有名字(没有inode)它的内容在内核中访问pipe的方式都是通过文件系统的API(read/write)

        它不能用open但是read/write又需要一个文件描述符

        所以在创建这个pipe的时候就必须要返回文件描述符

        pipe在创建时在内核中开辟一块缓冲区作为pipe文件的内容的存储空间同时返回两个文件描述符(一个用来读一个时用来写)

特点

           (1)pipe有两端一端时用来写一端是用来读

           (2)按顺序读不支持lseek光标移动

           (3)内容读走了就没有啦

           (4)pipe(无名管道) 随内核持续性

接口

    头文件

#include <unistd.h>

    函数功能

       pipe用来在内核中创建一个无名管道,pipefd用来保存创建好的无名管道的两个文件描述符pipe创建的管道默认是"阻塞方式"

    函数原型

       int pipe(int pipefd[2]);

    函数参数

       int pipefd[2]     //数组。 

              pipefd[0] 保存读的文件描述符

              pipefd[1] 保存写的文件描述符

          

    函数返回值

       成功返回0 

       失败返回-1同时errno被设置。

注意事项

    pipe(无名管道)的使用范围只要两个进程可以获取这个pipe(无名管道)的文件描述符就可以使用pipe(无名管道)来通信。

    pipe(无名管道)本身是全双工通信但是两个进程使用一个管道进行全双工通信就必须要有某种方式同步否则就可能自己读到自己写入的数据。所以在工程项目中我们一般使用两个或以上的管道来实现全双工通信一个读一个写人为的把它看成半双工通信。

    上面说到了pipe(无名管道)的使用范围而这个使用范围一般又是进程间有亲缘关系的进程除非通过某些方式将pipe(无名管道)告知其他进程。因此pipe(无名管道)一般都用于有亲缘关系的进程间通信。为什么呢其原因就是pipe(无名管道)它没有名字只能靠创建pipe(无名管道)时的文件描述符来确定pipe(无名管道)。记住这个特点我们再看FIFO有名管道。

代码实例

    一下代码实现创建一个pipe(无名管道)子进程先往pipe(无名管道)中写入数据然后再由父进程向pipe(无名管道)读取子进程写入的数据。

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


int main(int argc, char * argv [])
{	
	int fd[2]; 
	int p = pipe(fd);
	if(p == -1)
	{
		perror("pipe failed\n");
	}

	pid_t pid = fork();
	if(pid == -1)
	{
		perror("fork failed\n");
	}
	if(pid > 0) 
	{	
		int statues;
		int w = wait(&statues);
		if(w == -1)
		{
			perror("wait failed\n");
			return -1;
		}

		char buf[6] = {0};
		int r = read(fd[0],buf,5);
		if(r != 5)
		{
			perror("read fd[0] failed\n");
		}
		printf("read's content is %s\n",buf);
	}
	else if(pid == 0)
	{	
		int w = write(fd[1],"hello",5);
		if(w != 5)
		{
			perror("write fd[1] failed\n");
		}
	
	}
	return 0;
}

有名管道fifo

介绍

fifo是在pipe的基础上给fifo在文件系统中创建一个inode(它会在文件系统中有一个文件名)但是fifo文件的内容却是在内核中

           fifo的文件名随文件系统持续性的

           fifo的文件内容存在于内核随内核持续性的。

           fifo同pipe一样出除了fifo在文件系统中有一个文件名。所以特点也与pipe(无名管道)一样。

接口

fifo文件怎么创建呢

    通过mkfifo函数接口 

    头文件

       #include <sys/types.h>

       #include <sys/stat.h>

    函数功能

       用来在文件系统中创建一个fifo(有名管道)

    函数原型

       int mkfifo(const char *pathname, mode_t mode);

    函数参数

       const char *pathname     //要创建的有名管道在文件系统中的名字

       mode_t mode                 //创建的有名管道的权限有两种方式指定

                         (1)0660 0777 ...

                         (2)S_IRUSR   

    函数返回值

        成功返回0

       失败返回-1同时errno被设置。

注意事项

    FIFO(有名管道)它和PIPE(无名管道)类似除了它再文件系统中有一个名字。它可以被多个进程打开用来读或写。当进程用FIOF来交换数据时内核根本没有把数据写到文件系统中去而是保存在内核的内部因此FIFO在文件系统中没有内容它仅作为文件系统的一个引用入口提供一个文件名给其它进程去open它。

    在数据交换前FIFO的两端(read,write)必须都被打开。通常情况下你打开FIFO的一端会阻塞直到另外一端也被打开。

一个进程也可能以"非阻塞"方式(O_NONBLOCK)去打开。

    在这种情况下(以“非阻塞方式”)只读打开总会成功即便写端没有被打开;只写打开总会失败并且errno == EENXIO除非读端已经打开。

阻塞与非阻塞

阻塞方式 

    阻塞地读或写 

       读的时候如果没有数据则read会阻塞

       写的时候如果没有空间则write会阻塞 

             

非阻塞方式

    以非阻塞方式读或写 

       读的时候如果没有数据立即返回设置相应的错误码

       写的时候如果没有空间立即返回设置相应的错误码

代码实例

    一下代码实现两个无亲缘关系的进程间使用FIFO有名管道进程通信。一个进程用于读一个进程用于写。

        第一个进程用于将数据写进管道。

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

int main(int argc, char * argv [ ])
{
	//创建一个fifo有名管道文件
	int m =  mkfifo("./test.fifo", 0660);
	if(m == -1)
	{
		perror("mkfifo failed\n");
	}
	//打开管道文件
	int fd = open("./test.fifo",O_RDWR);
	if(fd == -1)
	{
		perror("open failed\n");
	}
	
	//写数据到管道文件
	char buf[11] = "I LOVE YOU";
	int w = write(fd, buf, 11);
	if(w != 11)
	{
		perror("write failed\n");
	}
	//关闭文件
	int c = close(fd);
	if(c == -1)
	{
		perror("close failed\n");
	}
	return 0;
}

        第二个进程用于将管道中的数据读出来。

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

int main(int argc, char * argv [ ])
{	
	int fd = open("./test.fifo",O_RDONLY);
	if(-1 == fd)
	{
		perror("open failedn");
	}

	char buf[6] = {0};
	int r = read(fd,buf,5);
	if(r != 5)
	{
		perror("read fd failed\n");
	}
	printf("read's content is %s\n",buf);
	itn c = close(fd);
	if(c == -1)
	{
		perror("close fd failed\n");
	}
	return 0;
}

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6