Linux进程间通信---管道篇

来源:互联网 发布:财务报销软件集思图友 编辑:程序博客网 时间:2024/06/09 22:13

一、进程间通信
每个进程各自有不同的用户空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲取,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信。
这里写图片描述
进程间通信的本质是让不用的进程能看到一份公共资源。
进程间通信主要用于:数据传输、资源共享、通知事件、进程控制。

二、管道(pipe)
1.管道,也叫匿名管道,是一种最基本的IPC机制,由pipe函数(系统调用)创建:

#include<unistd>int pipe(int filedes[2]);

返回值:成功返回 1,失败返回 0
参数:filedes输出型参数,在pipe内部对fileds进行修改,会改变它的函数。
这里写图片描述
调用pipe函数时在内核中开辟一块缓存区(称为管道)用于通信,它有一个读端,一个写端,然后通过filedes参数传出给用户程序两个文件描述符,filedes[0]指向管道的读端,filedes[1]指向管道的写端。所以管道在用户程序开起来就是一个打开的文件,通过 read(fileds[0]);或者 write(filedes[1]);向这个文件读写数据,实际上是在读写内核区缓冲区。

2.开辟管道之后的进程通信步骤
3.代码演示
父进程关闭写端,从管道中读数据,子进程关闭读端,向管道中写数据。
这里写图片描述
这里写图片描述
这里写图片描述
4.匿名管道通信的特点
(1)两个进程通过一个管道只能进行单向通信;
(2)只能用于具有血缘关系之间的进程通信,通常用于父子进程。
(3)管道的生命周期随进程。
(4)管道之间进行通信向上层提供的读写操作面向字节流的通信服务。
(5)管道自带同步机制。

5.相关概念扩充:
临界资源:两个进程同时访问一块资源。
临界区:访问临界资源的代码。
同步:让不同进程访问临界资源以相同的顺序进行访问称为进程同步。
互斥:任何时刻只能有且只有一个进程在访问临界资源。
原子性:一件事情要么做了,要么没做,没有中间状态。
饥饿:一个进程想要访问某种资源,但是由于优先级或其他原因一直无法访问该资源,此状态称为进程的饥饿状态。

三、命名管道(FIFO):
1.概念:
管道的一个不足之处是没有名字,因此,只能用于具有血缘关系的进程间通信,在命名管道(named pipe或PIPE)提出后,该限制得到了克服。命名管道不同于管道之处在于它提供了一个路径名与之关联,以FIFO的文件形式存储于文件系统中。命名管道是一个设备文件,因此,即使进程与创建fFIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO相互通信。值得注意的是,FIFO总是按照先进先出的原则工作,第一个被写入的数据将首先从管道中读出。

2.创建命名管道
linux下有两种方式创建命名管道,一是在Shell下交互地建立一个命名管道,二是在程序中使用系统函数建立命名管道。
(1)Shell方式下可使用mknod或mkfifo命令创建命名管道
例:

mknod namepipe

(2)创建命名管道的系统函数:mknod 和 mkfifo

#include<sys/types.h>#include<sys/stat.h>int mknod(const char *path,mode_t mod,dev_t dev);int mkfifo(const char *path,mode_t mod);

参数path为创建的命名管道的全路径名;
mod为创建的命名管道的模式,指名其存取权限;
dev为设备值,该值取决于文件创建的种类,它只在创建设备文件时才会用到。
这两个函数调用成功都返回 0,失败返回 -1;

mknod是比较老的函数,而使用mkfifo函数则更加的简单规范,所以建议在可能的情况下,尽量使用mkfifo而不是mknod。

(3)命名管道创建后就可以使用了,命名管道和管道的使用方法基本是相同的。只是使用命名管道时,必须先调用open()将其打开。因为命名管道是存在于一个硬盘上的文件,而管道则是存在于内存中的个特殊文件。
需要注意的是,调用open()打开命名管道的进程可能会被阻塞。
但如果同时用读写方式(O_RDWR)打开,则一定不会导致阻塞;
如果以只读方式(O_RDONLY)打开,则调用open()函数的进程将会被阻塞直到有写方打开管道;
同样以写方式(O_WRONLY)打开也会阻塞直到有读方式打开管道。

3.命名管道的代码演示:
打开两个终端,分别模拟客户端和服务器进行网络通信,客户端通过管道不断地向服务器发送数据,服务器从管道接收由客户端发来的数据。
客户端(client.c)
这里写图片描述
这里写图片描述
服务端(server.c)
这里写图片描述
这里写图片描述

原创粉丝点击