linux中ipc机制,【Linux】Linux进程通信与System V IPC机制

Linux进程通信基本概念

从原理上来看,进程通信的关键技术就是在进程间建立某种共享区,利用进程都可以访问共享区的特点来建立一些通信通道。如下图所示:

202360a15fab9a3abf7d147d7df124e9.png

其实,以前设计程序时使用的全局变量,就是一种可以在各个函数之间进行通信的手段,它所占用的内存空间就是程序中各个函数的共享区。但那时,由于各个函数都同属于一个进程,因此没有进程空间的障碍。所以,解决进程之间通信的就在于如何突破进程空间的障碍。

其实,在某些特殊情况下,两个进程之间并没有空间障碍。例如:用fork()创建了一个子进程之后,子进程与父进程尚未完全脱离关系之前,子进程和父进程处于同一个进程空间,这时是完全可以向定义一个全局变量来定义一个通信通道的,以实现父子进程之间的通信。虽然这是自然形成的一个结果,但并不是操作系统的功劳,却给人们一个启示:可以利用子进程创建伊始会与父进程共享一些资源(例如文件)的特点来构建通信通道,Linux在这方面的成果就是“管道”。

父子进程利用共享资源进行通信的示意图如下:

c630c5d12f7d22ce88872f6ec5dcd65a.png

对于那些具有进程空间障碍的进程通信可以利用页框共享技术来实现。例如,一个由3个进程共享的页框示意图如下:

9a8175e45807924c85d7f8db9f5e8055.png

另外,还可以当进程处于内核期间利用内核空间来进行通信,例如:

dcbbedb770d5b5addfa36451047b2d47.png

总之,通信的关键就是想办法在进程之间创建共享区域来传递数据。

System V IPC机制简介

Linux的通信手段基本都继承自Unix。历史上对Unix的发展做出重大贡献的两大主力:AT&T的贝尔实验室和加州大学伯克利分校(BSD)。在通信方面,前者主要对单个计算机内的进程通信机制进行了改进和扩充,形成了System V IPC;后者则主要在计算机间,基于嵌套字(socket)的进程间通信机制方面做出了重要贡献。

早期的Unix IPC包括管道、FIFO和信号,后期的System V IPC则主要包括System V消息队列、System V信号量集和System V共享内存。

Linux从一开始就严格遵守Unix的设计思路,从而形成了Linux通信机制,如下图所示:

2573a4d57a5eb8b3ecb96993fcea4ea9.png

Linux进程通信的主要手段有:

匿名管道(pipe)以及命名管道(named pipe):匿名管道可用于具有亲属关系进程间的通信;命名管道克服了匿名管道没有名称的限制,从而允许无亲属关系进程间的通信;

信号(signal):信号是一种通知性的通信方式,当某种事件发生时,用于向接收进程发出通知,根据需要,接收进程可以对通知做出某种反应,也可以不加任何理睬;

消息队列:消息队列是由多个信号组成的链表,而消息是一种有结构的数据。与信号比,消息队列能承受更大的信息量;与管道比,消息队列克服了管道只能承载无格式字节流以及缓冲区大小受限的缺点。比较完备;

共享内存:共享内存是多个进程可以共同访问一块内存空间,是最快的通信方式。但它不具备同步和互斥机制,往往需要程序上使用信号量或锁与它配合;

信号量集(semaphore):主要作为进程间以及同一进程不同线程之间的同步方式;

嵌套字(socket):主要用来实现网络上不同机器之间的通信。

在上述System V IPC通信机制中,通常将通信装置叫做IPC(Inter-Process Communication,进程间通信)对象。为了对这些对象进行统一管理,系统为他们定义了一些统一的数据结构和标识。

IPC标识符

在IPC中,对于消息队列、共享内存和信号量集这些IPC对象,都用非负的整数来作为对象的标识。不同种类对象的标识是各自独立编制的,即同一个标识符可能代表共享内存,也可能代表消息队列或信号量集。

IPC键值

为了能唯一的标识一个对象,在IPC中,每创建一个对象还要为其指定一个键值,这个键值是一个长整型数。

kern_ipc_perm结构

系统为每一个IPC对象,都为其创建一个描述该对象基本信息的ipc_perm结构。该结构主要用于访问权限检查。kern_ipc_perm的定义如下:

struct kern_ipc_perm

{

spinlock_tlock;

intdeleted;

intid;

key_tkey; //对象的键值

uid_tuid; //用户标识

gid_tgid; //用户组标识

uid_tcuid; //对象创建者的用户标识

gid_tcgid; //对象创建者的用户组标识

mode_tmode; //对象的操作权限

unsigned longseq; //已创建的IPC对象的数目

void*security; //与对象标识相关的序列号

};

当一个对象被创建时,kern_ipc_perm除了seq之外的所有域都会被赋予相应的数值。在对象存在期间,IPC对象的创建者和超级用户,可以调整控制函数xxxctl()来修改kern_ipc_perm结构中的属性。控制函数名称中的xxx的含义如下图所示:

2ee69202c87670d0346333a1fc24040b.png

IPC对象的生命期

IPC对象是全局对象,对象一经创建就由系统进行管理,它们的生命期与创建它的进程生命期无关。

IPC对象的操作函数

为了实现对象的操作,系统在函数库中为用户提供了一个IPC对象操作函数ipc()。其原型如下:

int ipc(uint call, int first, int second, int third, void __user *ptr, long fifth);

ipc()中的第一个参数call叫做操作码。不同的操作码对应着不同的IPC对象的不同操作函数。该操作码定义如下:

#define SEMOP 1

#define SEMGET 2

#define SEMCTL 3

#define SEMTIMEDOP 4

#define MSGSND11

#define MSGRCV12

#define MSGGET13

#define MSGCTL14

#define SHMAT21

#define SHMDT22

#define SHMGET23

#define SHMCTL24

凡是以SEM开头的操作码都表示信号量集操作函数,以MSG开头的都表示是消息队列操作函数,以SHM开头的都表示是内存共享操作函数。

其实,上述这种用操作码来区分不同对象的不同操作并不方便(至少使程序的可读性变差)。所以,Linux系统函数库又分别定义了12个函数来完成不同的操作。其中,用于信号量集的函数为semop()、semget()、semctl()、semtimedop();用于消息队列的函数为msgsnd()、msgrcv()、msgget()、msgctl();用于共享内存的函数为shmat()、shmdt()、shmgat()、shmctl()。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值