您的位置:首页 > 其它

UNPv2:进程间通信(一)简介

2015-09-09 12:04 190 查看
想知道如何为网络开发软件,必须先理解进程间通信(IPC)。 ——Richard
Stevens

一个大功能或大应用,可以将其设计为单个庞大的程序,而更好的方式是将其设计为一组相互通信的程序片段。一般是用多个进程来实现,其中每个进程包含几个线程。这样,进程内部的线程之间需要通信,不同的进程之间需要通信。

进程间通信可以达到数据传输、数据共享、事件通知、进程控制等目的,其中:

数据传输:一个进程将数据发送给另一个进程。

数据共享:多个进程读写共享数据。

事件通知:一个进程向其他进程发送消息,通知它(们)发生了某种事件。

进程控制:一个进程希望完全控制另一个进程(如debug进程)的执行,能够拦截(如debug)进程的所有陷入和异常,并能够及时知道它的状态改变。

1进程间通信方式

Linux的进程通信方式都是从UNIX上继承下来的,而对Unix发展做出重大贡献的两大主力AT&T的贝尔实验室和BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间通信方面的侧重点有所不同。前者对Unix早期的进程间通信方式进行了系统的改进和扩充,形成了“System
V IPC”,通信进程局限在单个主机内;后者则跳过了该限制,形成了基于套接口(socket)的进程间通信机制。Linux则把两者都继承下来。(转载)



Posix是“可移植操作系统接口”(PortableOperating System Interface),它并不是一个单一的标准,而是一个由电气与电子工程师学会及IEEE开发的一系列标准。Posix标准还是由ISO(国际标准化组织)和IEC(国际电工委员会)采纳的国际标准。
XSI是X/Open系统接口(X/OpenSystem
Interface)。Open Group是由X/Open公司(1984年成立)和开放软件基金会(OSF,1988年成立)于1996年合并而成的组织。它是由厂家、业界最终用户、政府部门和学术机构组成的国际组织。
因在System V系统上提出了进程通信的IPC机制(如消息队列、信号量和共享内存),故通常称为System
V IPC。又因为后来被收录到Unix的XSI标准之中故又称为XSI
IPC。所以System V IPC和 XSI IPC实际上指的是同一种东西。



2共享信息方式

一个系统上运行多个进程,每个进程都有各自的地址空间。UNIX进程间的信息共享可以有多种方式。



左边的两个进程共享存留于文件系统中某个文件上的某些信息。当一个文件有待更新时,某种形式的同步是必要的。如read、write、lseek等,为访问这些信息,每个进程都得穿越内核。
中间的两个进程共享驻留于内核中的某些信息。如管道、System V消息队列、System
V信号量。访问共享信息的每次操作涉及对内核的一次系统调用。
右边的两个进程有一个双方都能访问的共享内存区。每个进程一旦设置好改共享内存区,就能根本不涉及内核而访问其中的数据。共享该内存区的进程需要某种形式的同步。

3 IPC

3.1 IPC对象

IPC对象可以是消息队列、信号量、共享存储等三个类型的任意一种。它是活动在内核级别的一种进程间通信的工具。
IPC对象通过它的标识符来引用和访问,该标识符是一个非负整数,它唯一的标识了一个IPC对象。当IPC对象被创建或删除时,对应的标识符连续加1,直到达到一个整型数的最大正值,然后又回转到0.
IPC对象的标识符只解决了内部访问一个IPC对象的问题,如何让多个进程都访问某一个特定的IPC对象还需要一个外部键(key),每个IPC对象都与一个键相关联。这样就解决了多个进程在一个IPC对象上汇合的问题。

3.2 IPC对象查看与删除

由于System V IPC的三种类型不是以文件系统中的路径名标识的,因此使用标准的ls和rm程序无法看到它们,也无法删除它们。不过实现了这些类型IPC的任何系统都提供两个特殊的程序:ipcs和ipcrm。
ipcs输出有关System VIPC特性的各种信息,ipcrm则删除一个System
V消息队列、信号量或共享内存区。

lincoln@ubuntu:~$ ipcs

------ Shared Memory Segments --------
key shmid owner perms bytes nattch status

------ Semaphore Arrays --------
key semid owner perms nsems

------ Message Queues --------
key msqid owner perms used-bytes messages

lincoln@ubuntu:~$ man ipcrm
IPCRM(1) Linux Programmer's Manual IPCRM(1)

NAME
ipcrm - remove a message queue, semaphore set or shared memory id

SYNOPSIS
ipcrm [ -M key | -m id | -Q key | -q id | -S key | -s id ] ...



3.3 IPC对象的持续性

   IPC对象的持续性是该对象一直存在多长时间。如图四,展示了三种类型的持续性。



3.4 IPC命名空间

当两个或多个无亲缘关系的进程使用某种类型的IPC对象彼此交换信息时,该IPC对象必须有一个某种形式的名字(name)或标识符(identifier),这样其中一个进程(往往是服务器)可以创建该IPC对象,其余进程则可以指定同一个IPC对象。
对于一个给定的IPC类型,其可能的名字的集合称为它的命名空间(name
space)。命名空间非常重要,因为对于除普通管道以外的所有形式的IPC来说,名字是客户与服务器彼此连接以交换信息的手段。

IPC类型
命名空间
标识
管道

FIFO
没有名字

路径名
描述符

描述符
Posix消息队列

Posix有名信号量

Posix基于内存的信号量

Posix共享存储区
Posix IPC名字

Posix IPC名字

没有名字

Posix IPC名字
mqd_t值

sem_t值

sem_t指针

描述符
System V消息队列

System V信号量

System V共享内存区
key_t键

key_t键

key_t键
System V IPC标识符

System V IPC标识符

System V IPC标识符
TCP套接字

UDP套接字

Unix域套接字
IP地址和TCP端口

IP地址和UDP端口

路径名
描述符

描述符

描述符

3.5 POSIX IPC

 
消息队列
信号量
共享内存区
头文件
<mqueue.h>
<semaphore.h>
<sys/mman.h>
创建、打开或删除IPC的函数
mq_open()

mq_close()

mq_unlink()
sem_open()

sem_close()

sem_unlink()
shm_open()

shm_unlink()
控制IPC操作的函数
mq_getattr()

mq_setattr()
 
ftruncate()

fstat()
IPC操作函数
mq_send()

mq_receive()

mq_notify()
sem_wait()

sem_trywait()

sem_post()

sem_getvalue()
mmap()

munmap()

3.6 System V IPC

 
消息队列
信号量
共享内存区
头文件
<sys/msg.h>
<sys/sem.h>
<sys/shm.h>
创建或打开IPC的函数
msgget()
semget()
shmget()
控制IPC操作的函数
msgctl()
semctl()
shmctl()
IPC操作函数
msgsnd()

msgrcv()
semop()
shmat()

shmdt()
3.6.1key_t键和ftok函数
从上述IPC命名空间可知,三种类型的SystemV
IPC使用key_t值作为它们的名字。头文件<sys/types.h>把key_t这个数据类型定义为一个整数(至少32位)。这个整数值通常是由ftok函数赋予的。
函数ftok把一个已存在的路径名和一个整数标识符转换成一个key_t值,称为IPC键。

#include <sys/ipc.h>

key_t ftok(const char *pathname, int id);返回:成功返回IPC键,出错返回-1
该函数把从pathname导出的信息与id的低序8位组合成一个整数IPC键。ftok的典型实现调用stat函数,然后组合一下三个值:
1)stat结构的st_dev成员(pathname所在的文件系统的信息)
2)stat结构的st_info成员(pathname在文件系统内的索引节点号)
3)id的低序8位
如果pathname不存在,或者对于调用进程不可访问,ftok就返回-1.注意,路径名用于产生键的文件不能是在服务器存活期间由服务器反复创建并删除的文件,因为该文件每次创建时由系统赋予的索引节点号很可能不一样,于是对下一个调用者来说,由ftok返回的键也可能不同。
3.6.2ipc_perm结构
内核给每个IPC对象维护一个信息结构,其内容跟内核给文件维护的信息类似。

头文件<sys/ipc.h>

struct ipc_perm

{

uid_t  uid;//拥有者用户ID

gid_t  gid;//拥有者组ID

uid_t cuid;//创建者用户ID

dig_t cgid;//创建者组ID

mode_t mode;//读写权限

ulong_t seq;//槽位使用序列号,即IPC对象的维护计数器

key_t key;//IPC键

};
3.6.3创建与打开IPC通道
创建或打开一个IPC对象的三个XXXget函数,都有名为keyoflag的参数。

int msgget(key_tkey, int
oflag);

int semget(key_tkey,int nsems, int
oflag);

int shmget(key_tkey, size_t size, int
oflag);
key是类型为key_t的IPC键。对于key值,应用程序有两种选择:
1)调用ftok,给它传递pathname和id。
2)指定key为IPC_PRIVATE,这将保证会创建一个新的、唯一的IPC对象。



       oflag参数用于1)指定IPC对象的读写权限位,2)并选择是创建一个新的IPC对象还是访问一个已存在的IPC对象。

1)指定IPC对象的读写权限位

数字值

八进制
符号
 

说明
消息队列
信号量
共享内存区
0400

0200
MSG_R

MSG_W
SEM_R

SEM_A(注:alter)
SHM_R

SHM_W
用户读

用户写
0040

0020
MSG_R >> 3

MSG_W >>3
SEM_R>>3

SEM_A>>3
SHM_R>>3

SHM_W>>3
组读

组写
0004

0002
MSG_R>>6

MSG_W>>6
SEM_R>>6

SEM_A>>6
SHM_R>>6

SHM_W>>6
其他用户读

其他用户写
2)创建新IPC对象还是访问已存在IPC对象

oflag参数
key不存在
key已存在
无特殊标志,如0为参数

IPC_CREAT

IPC_CREAT | IPC_EXCL
出错,errno=ENOENT

成功,创建新对象

成功,创建新对象
成功,引用已存对象

成功,引用已存对象

出错,errno=EEXIST
 

参考:
《UNIX网络编程》卷2:进程间通信
深刻理解Linux进程间通信



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息