《应用编程 — IPC》

1.IPC

IPC:interprocess communication-进程间通信

  Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程间不能互相访问,要交换数据必须通过内核,在内核中开辟一块缓存区,进程1把数据从用户空间拷贝到内存缓冲区,进程2再从内存缓冲区中把数据读走,内核提供的这种机制称为进程间通信(IPC)。

进程间通信的实质?

  不同的两个程序虽然0-4G内存地址空间不同,但两个程序的内核区在物理内存上是同一块。共享(物理内存中)同一内核区。——两个程序打开同一个文件,系统会在内核区维护打开文件的结构体,两个程序打开的是同一个结构体。

 

有哪些常用的进程间通信方法? 

①匿名管道(PIPE)和有名管道(FIFO):最简单

②信号(SIGNAL):系统的开销最小 

③共享映射区(MMAP):可以在无血缘关系的进程间通信

④本地套接字(SOCKET):最稳定(但是比较复杂)

 

IPC方法比较

  pipe-优点:实现简单;缺点:单向通信,只能用于有血缘关系进程间。   

  fifo-优点:可以在非血缘关系进程间。    信号-优点:开销小。   

  共享内存-优点:可以用于非血缘关系进程间;缺点:比较复杂。   

  本地套接字-优点:稳定性好;缺点:实现复杂。   

  共享内存和fifo的区别:在于数据是否可以反复读取;fifo是用队列实现的,不能反复读取;共享内存是Linux内核借助缓冲区,通过内存来实现,可以反复读取。

 

2.标识符和键

  每个内核中的IPC结构(消息队列、信号量或共享存储段)都用一个非负整数的标识符(identifier)加以引用。

  标识符是IPC对象的内部名。为此,每个IPC对象都与一个键(key)相关联,将这个键作为该对象的外部名。

  无论何时创建IPC结构(通过调用msgget、semget或shmget创建),都应指定一个键。这个键的数据类型是基本系统数据类型key_t,通常在头文件<sys/types.h>中被定义为长整型。这个键由内核变换成标识符。

  有多种方法使客户进程和服务器进程在同一IPC结构上汇聚。

  1.服务器进程可以指定键IPC_PRIVATE创建一个新的IPC结构,将返回的标识符存放在某处(如一个文件)以便客户进程取用。键IPC_PRIVATE保证服务器进程创建一个新IPC结构。这种技术的缺点:文件系统操作需要服务器进程将整型标识符写到文件中,此后客户进程又要读取这个文件取得此标识符。

  2.可以在一个公用头文件中定义一个客户进程和服务器进程都认可的键。然后服务器进程指定此键创建一个新的IPC结构。这种方法的问题是该键可能已与一个IPC结构相结合,在此情况下,get函数(msgget、semget或shmget)出错返回。服务器进程必须处理这一错误,删除已存在的IPC结构,然后试着再创建它。

  3.客户进程和服务器进程认同一个路径名和ID(0~255之间的字符值),调用函数ftok函数将这两个值变换成一个键。然后再方法(2)中使用此键。

  ftok提供的唯一服务就是由一个路径名和ID产生一个键

#include <sys/ipc.h>

key_t  ftok(const char *path, int id);

返回值:成功,返回键;失败返回-1

 

  3个get函数(msgget、semget和shmget)都有两个类似的参数:一个key和一个整形的flag。在创建新的IPC结构(通常由服务器进程创建)时,如果key是IPC_PRIVATE或者和当前某种类型的IPC结构无关,则需要指明flag的IPC_CREAT标志位。为了引用一个现有队列(通常由客户进程创建),key必须等于队列创建时指明的key的值,并且IPC_CREAT必须不被指明。

  注意:绝不能指定该IPC_PRIVATE作为键来引用一个现有队列,因为这个特殊的键值总是用于创建一个新队列。为了引用一个用IPC_PRIVATE键创建的现有队列,一定要知道这个相关的标识符,然后在其他IPC调用中(如msgsnd、msgrcv)使用该标识符,这样可以绕过get函数。

  如果希望创建一个新的IPC结构,并且要确保没有引用具有同一标识符的一个现有IPC结构,那么必须在flag中同时指定IPC_CREAT和IPC_EXCL位。这样做了以后,如果IPC结构已经存在就会造成出错,返回EEXIST(这与指定了O_CREAT和O_EXCL标志的open相类似)。

 

posted @ 2020-02-11 20:50  一个不知道干嘛的小萌新  阅读(398)  评论(0编辑  收藏  举报