当前位置: 首页 > 科技观察

Linux中的命名管道和无名管道

时间:2023-03-14 12:12:48 科技观察

今天就带小伙伴们一起来学习一下Linux中命名管道和无名管道的使用。先简单介绍一下有名管道和无名管道相关的内容,然后再学习功能。最后排代码!1无名管道和有名管道的区别管道分为无名管道(pipe)和有名管道(FIFO)。无名管道只能用于同一祖先的两个进程之间的通信,因为自己创建的管道在其他进程中是不可见的。命名管道可用于同一系统上任意两个进程之间的通信。1)无名管道创建无名管道后,相当于操作文件。无名管道的读端被当作一个文件,写端也被当作一个文件。pipe用于创建,read、write、close用于操作。①匿名管道通信是单向的,有固定的读端和写端。②进程从管道中读取数据后,管道中的数据不存在。③当进程读到空管道时,进程会阻塞。④当进程向满管道写入数据时,进程会阻塞。⑤管道的最大容量为64KB,可以通过宏PIPE_BUFFERS来设置。下面添加两个未命名管道的两个描述。<1关于共同祖先进程的说明。管道可用于任何两个或多个相关进程之间的通信,只要管道是在创建子进程的一系列调用之前通过公共祖先进程创建的。例如,管道可用于进程与其后代之间的通信。第一个进程创建管道,然后创建一个子进程,子进程创建第一个进程的孙进程。管道通常用于两个兄弟进程之间的通信——它们的父进程创建管道,并创建两个子进程。<2关于未命名管道半双工的注释。一般来说,流水线都是半双工的,有些系统已经实现了全双工的功能,但是为了移植方便,尽量使用半双工方式来使用流水线。在半双工的情况下,管道的两端在一个进程中相互连接,数据需要通过内核流经管道。单个进程读写pipe是没有问题的,但是应用更多的是两个进程之间的通信,这时候就出现了竞争的问题。如果创建两条管道,需要注意死锁问题。如果两个进程都尝试从空管道读取或写入满管道,则会发生死锁。这时由于半双工的原因,需要关闭不需要的读端和写端。下图是父子进程之间的通信示意图。图2)FamouspipesFamouspipes也称为FIFO文件,其操作类似于文件操作,需要创建、打开、关闭等操作。创建用mkfifo,删除用unlink,读写用read,write,打开关闭用open,close。FIFO文件操作与普通文件操作的区别如下:①读取FIFO文件的过程只能以“RDONLY”方式打开FIFO文件。②写FIFO文件的过程只能以“WRONLY”方式打开FIFO文件。③FIFO文件中的内容被读取后,消失。但是普通文件中的内容在读取后仍然存在。2Linux下的无名管道1)pipe函数pipe函数用于创建一个无名管道。①函数原型。intpipe(intpipefd[2])②头文件。包括③参数。pipefd[0]:读取管道。pipefd[1]:写入管道。④返回值。成功:0失败:-1.3Linux下的命名管道1)mkfifo函数mkfifo函数用于创建命名管道。①函数原型。intmkfifo(constchar*pathname,mode_tmode)②头文件。includeinclude③参数。pathname:要创建的fifo文件名,带路径。mode:要创建的fifo文件的访问权限。④返回值。成功:0。失败:-1。2)unlink函数unlink函数用于删除一个众所周知的管道。实际上,它可以删除先进先出文件和普通文件。①函数原型。intunlink(constchar*pathname)②头文件。包括③参数。pathname:要创建的fifo文件名,带路径。④返回值。成功:0。失败:-1。3)open函数open函数用于打开一个命名管道。①函数原型。inopen(constchar*pathname,intflags)inopen(constchar*pathname,intflags,mode_tmode)②头文件。#include#include#include③参数。pathname:要打开的文件名(包括路径)。flags:文件打开标志(这里只介绍两个,更多可以在man2open中查看)。O_APPEND:打开文件进行追加。O_CREAT:当打开的文件不存在时,创建文件。mode:flags中必须使用O_CREAT标志,mode记录了要创建的访问权限。④返回值。成功:返回文件描述符。失败:返回-1。4)read函数read函数用于读取一个众所周知的管道。①函数原型。ssize_tread(intfd,void*buf,size_tcount)②头文件。#include③参数。fd:要读取的文件的文件描述符。buf:读缓冲区的起始地址(读数据存放在buf指向的空间)。count:读取的字节数。④返回值。成功:读取的字节数。失败:返回-1。5)write函数write函数用来写一个命名管道。①函数原型。ssize_twrite(intfd,constvoid*buf,size_tcount)②头文件。#include③参数。fd:文件描述符。buf:文件数据缓冲区。count:要写入的数据字节数。④返回值。成功:写入的字节数。失败:返回-1。6)关闭函数关闭函数用于关闭命名管道。①函数原型。intclose(intfd)②头文件。#include③参数。fd:要关闭的文件描述符。④返回值。成功:返回0。失败:返回-1。4示例代码下面用两个小程序来使用上面介绍的有名管道和无名管道。1)无名管道用例示例代码如下,说明在代码注释,图片。PipeTest.c.#include#include#includevoidmain(void){pid_tpid=0;//进程的pidintpipefd[2];//读写的文件描述符writepipecharbuf[20];//数据缓冲pipe(pipefd);//创建管道pid=fork();//创建子进程if(pid>0)//父进程{close(pipefd[0]);//这是一个习惯,关闭不用的管道write(pipefd[1],"Testpipe!",11);//向管道写入数据wait();//等待子进程退出close(pipefd[1]);//关闭文件exit(0);//进程退出}if(pid==0)//子进程{close(pipefd[1]);//这是习惯,关闭不用的pipesread(pipefd[0],buf,11);//读取管道内容并打印printf("\nThepipe'scontextis%s\n\n",buf);//子进程可以读取pipe写入的内容parentprocesstothepipeTest!close(pipefd[0]);//关闭管道exit(0);//进程退出}}运行结果如下:2)名管道示例代码如下如下,描述在代码注释中。写FIFO.c。#include#include#include#includeintmain(void){intfifofd;//FIFO文件描述符intret;mkfifo("/tmp/fifo",0666);//创建FIFO文件fifofd=open("/tmp/fifo",O_WRONLY);//打开FIFO文件ret=write(fifofd,"TestFIFO!",11);//写入数据到FIFO文件,等待读取成功再返回close(fifofd);//关闭FIFO文件return0;}ReadFIFO.c.#include#include#include#includevoidmain(void){intfifofd;//管道文件描述符charbuf[20];//数据缓冲区mkfifo("/tmp/fifo",0666);//创建FIFO文件fifofd=open("/tmp/fifo",O_RDONLY);//打开FIFO文件read(fifofd,buf,11);//读取FIFO文件printf("\nTheFIFO'scontentis%s\n\n",buf);//显示读取FIFO文件的内容unlink("/tmp/fifo");//删除FIFO文件}运行结果如下:先运行WriteFIFO操作,此时会阻塞,然后运行ReadFIFO,打印并解除阻塞。本文转载自微信公众号“嵌杂军”,可通过以下二维码关注。转载本文请联系嵌入式杂军公众号。