1 前言
如上图所示是System V IPC相关的接口表,System V IPC未遵循“一切都是文件”的Unix哲学,而是采用标识符ID和键值来标识一个System V IPC对象.每种System V IPC都有一个相关的get调用(表中的“创建或打开对象”一行),该函数返回一个整型标识符ID,System V IPC后续的函数操作都要作用在该标识符ID上.System V IPC对象的作用范围是整个操作系统,内核没有维护引用计数.调用各种get函数返回的ID是操作系统范围内的标识符,对于任何进程,无论是否存在亲缘关系,只要有相应的权限,都可以通过操作System V IPC对象来达到通信的目的,System V IPC对象具有内核持久性.哪怕创建System V IPC对象的进程已经退出.哪怕有一段时间没有任何进程打开该IPC对象.只要不执行 删除操作或系统重启.后面启动的进程依然可以使用之前创建的System V IPC对象来通信.
此外,我们也无法像操作文件一样来操作System V IPC对象.System V IPC对象在文件系统中没有实体文件与之关联.我们不能用文件相关的 操作函数来访问它或修改它的属性.所以不得不提供专门的系统调用(如msgctl,semop等)来操作这些对象.在shell中无法用ls查看存在的IPC对象,无法用rm将其删除,也无法用chmod来修改它们的访问权限.幸好Linux提供了ipcs,ipcrm和ipcmk等命令来操作这些对象由于System V IPC对象不是文件描述符,所以无法使用基于文件描述符的多路转接I/O技术(select、poll和epoll等),这个缺点会给编程带来一些不便之处。
1.1 标识符与IPC Key
System V IPC对象是靠标识符ID来识别和操作的,该标识符要具有系统唯一性,这和文件描述符不同,文件描述符是进程内有效的,一个进程的文件描述符4和另一个进程的文件描述符4可能毫不相干,但是IPC的标识符ID是操作系统的全局变量,只要知道该值(哪怕是猜测获得的)且有相应的权限,任何进程都可以通过标识符进行进程间通信,三种IPC对象操作的起点都是调用相应的get函数来获取标识符ID,如消息队列的get函数为:
int msgget(key_t key, int msgflg);
key值的选择:
1.我们可以随机选用一个整数值作为key值,需要注意的是,要防止无意中选择了重复的key值,从而导致不要通信的进程之间意外通信,引发程序混乱,一个技巧就是将项目要用到的key放入同一个头文件中,方便检查是否有重复的key值
2.使用IPC_PRIVATE,使用IPC_PRIVATE来得到IPC标识符会存在一个问题,即不相干的进程无法通过key值得到同一个IPC标识符.因为IPC_PRIVATE总是创建一个新的IPC对象,如图所示.因此IPC_PRIVATE一般用于父子进程,父进程调用fork之前创建IPC对象,创建子进程后,子进程也就继承了IPC标识符,从而父子进程可以通信.当然无亲缘关系的进程也可以使用IPC_PRIVATE,只是稍微麻烦了一点,IPC对象的创建者必须想办法将IPC标识符共享出去,让其他进程有办法获取到,从而通过IPC标识符进行通信.
3.使用ftok函数,所谓ftok是file to key的意思,多个进程通过同一个路径名获得相同的key值,进而得到同一个IPC标识符,其接口定义如下: