标签:表示 描述符 过程 虚拟 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.bin和b.bin的MD5码是否一致。
标签:表示 描述符 过程 虚拟 RoCE 实验代码 取数 特殊 技术
原文地址:https://www.cnblogs.com/liangda/p/9949623.html