码迷,mamicode.com
首页 > 系统相关 > 详细

跟着iMX28x开发套件学linux-067

时间:2018-11-13 02:37:03      阅读:134      评论:0      收藏:0      [点我收藏+]

标签:表示   描述符   过程   虚拟   RoCE   实验代码   取数   特殊   技术   

七、linux应用编程之五:管道

进程间通信有多种方式,管道是其中一种。管道分为匿名管道和命名管道,匿名管道仅用于父子进程之间通信,没有实际文件。而命名管道可以实现任意进程间的通信,在系统中需要创建一个fifo文件作为管道。

管道的理解:无论是匿名管道还是命名管道,都可以把管道看做一个文件,进程A给这个文件写数据,进程B从这个文件读数据,那么进程A就可以给进程B传输数据了。而重点在于,匿名管道没有实际文件要怎么实现,还有如何保证进程A,B之间的通信同步(即进程A发送数据的时候,是不是进程B需要这个数据的时候)。

匿名管道

1) 创建管道:匿名管道没有实际的文件,想象出一个虚拟的文件,父进程给这个文件写数据,子进程从这个文件读数据,完成父子进程间的通信。既然想象成文件,那读写数据就需要文件描述符,但是这个文件又是虚拟的,无法通过open()函数获得文件描述符。实际上系统只需要知道哪个是文件描述符即可,文件描述符的内容是什么没有影响。所以可以int声明文件描述符,然后调用int pipe(int pipefd[2]);函数对这个文件描述符进行注册即可,当然要检查注册是否成功,所以有以下代码,创建管道:

 技术分享图片

PS:代码中文件描述符用了int pipefd[2],一般文件描述符都是int fd,实际上pipefd[2]并不是两个文件的意思,而是一个文件的两个端口,读端口和写端口。linux系统定义pipefd[1]是写端口,pipefd[0]是读端口,匿名管道实际模型更加接近于下图:

 技术分享图片

2) 将数据写入匿名管道:父子进程都可以是数据的接收方或者数据的发送方,但是不能同时是数据的发送方和接收方,所以匿名通道实际上是一个半双工通信。 假设父进程时发送方,那父进程应当关闭pipefd[0],然后在pipefd[1]写入要发送的数据。父进程发送数据代码如下:

   技术分享图片

代码说明:在父进程中先关闭输入端口pipefd[0],接着在pipefd[1]写入要发送的数据,这里的数据是运行程序时的第二个参数。发送完成之后关闭输出端口pipefd[1],最后给子进程发送wait()。

3) 从匿名管道中读取数据:上面程序中父进程已经把数据写入了匿名通道,子进程应当把管道中的数据读取出来,完成一次进程通信。子进程中先关闭匿名通道的输出端口pipe[1],然后读取匿名通道中的内容,判断是否读取完毕,然后将读取到的内容打印到屏幕上,观察与运行程序时的第二个参数是否相同。代码如下:

 技术分享图片

代码说明:在读取数据的时候,应该一个字节一个字节的读,当read()函数返回-1的时候代表数据已经全部读取。

4) 通信同步问题:有四种特殊情况需要注意。

① 写端开启,读端开启,当读端读出数据时,若匿名管道内没有数据,读端进程将在read()处阻塞。

② 写段关闭,读端开启,当读端读出数据时,匿名管道中的数据被全部读出,读端进程的read()将会返回0

③ 写端开启,读端关闭,若写端进程试图运行write()函数时,写端进程将会收到信号SIGPIPE,并终止。

④ 写端开启,读端开启,但是读端没有进行read(),而写端一直运行write(),等到匿名管道被写满之后,写端进程将在write()处阻塞。

5) 匿名管道完整实验代码:

 技术分享图片

 技术分享图片

程序运行结果:

 技术分享图片

命名管道

1) 创建通道:命名通道是有具体文件的fifo,可以时间无关进程间的通信,所以创建命名通道的过程跟创建文件是一样的。在创建命名通道之前,要用acess(fifo_name, F_OK);函数检查通道文件是否存在,若存在返回0,不存在返回-1,根据返回的结果决定是否创建命名管道。创建过程代码如下:

  技术分享图片

2) 写端将数据写进命名管道:跟写数据进文件一样,写入数据之前要先打开文件。需要注意的是,当使用只写(O_WRONLY)模式打开命名管道时,若没有进程使用只读(O_RDONLY)模式打开命名管道,则用只写模式打开命名管道的进程将会阻塞,直到有进程使用只读模式打开命名管道。当然,如果一个进程使用读写(O_RDWR)模式打开命名管道时,不会阻塞。打开命名管道以及写数据进管道的代码如下:

 技术分享图片

3) 读端从命名管道读取数据:与从文件读数据一样,读取数据之前要先打开文件,然后写入,代码如下:

 技术分享图片

4) 完整实验代码:进程A创建命名管道,并复制一个文件的内容到管道。进程B从管道中读取数据,然后写入到另一个文件中。最后通过MD5校验查看两个代码的内容是否相同。

进程A代码:

技术分享图片

技术分享图片

进程B代码:

 技术分享图片

技术分享图片

程序运行结果,先运行进程A,再运行进程B

 技术分享图片

说明:运行进程A之前先创建进程A要用到的文件a.bin(在程序中文件的打开方式没写O_CREAT),然后运行进程A,注意用的指令是./processA a.bin &,表示程序后台运行,因为以只写模式打开命名管道时,进程会阻塞,如果不后台运行,这个终端将无法操作。接着运行进程B,运行进程B之后,进程A结束阻塞状态,从a.bin中读取数据,然后写到管道中,进程B从管道中读取数据,然后写到b.bin中。运行结束后,运行md5sum指令,查看a.binb.binMD5码是否一致。

 

跟着iMX28x开发套件学linux-067

标签:表示   描述符   过程   虚拟   RoCE   实验代码   取数   特殊   技术   

原文地址:https://www.cnblogs.com/liangda/p/9949623.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!