在linux中,system v IPC 也为进程间通信的一种
System V 消息队列
System V 信号量
System V 共享内存
1、System V IPC 未遵循“一切都是文件”的linux哲学,而是采用的标识符ID和键值来标记一个System V IPC 对象,每种System V IPC 都有一个与之相关的get(用于创建或打开一个对象),该函数返回一个整形标识符ID,System V IPC 后续的函数操作都要作用在该标识符ID上
2、System V IPC 对象作用范围为整个操作系统,内核没有维护引用计数,调用各种get()函数返回的ID是操作系统的标识符,对于任何进程,无论是否存在血缘关系,只要有相应的权限,都可以通过System V IPC对象来达到通信的目的
3、System V IPC对象具有内核持久性(随内核),哪怕进程已经退出,只要不执行删除或系统重启,对象依旧存在,后面启动的进程依然可以用之前创立的System V IPC 对象进行通信
4、我们无法像操作文件一样来操作System V IPC对象,它在系统中没有实体文件与之关联,它也不是文件描述符
System V IPC ——标识符与IPC key :
System V IPC对象是靠标识符ID来识别操作的,该标识符要具有系统唯一性,这和文件描述符不同,文件描述符是进程内部有效的,一个进程的文件描述符4与另一个进程的文件描述符4可能毫不相干,但是IPC的标识符ID是操作系统的全局变量,只要知道该值且具有一定的权限,任何进程都可以通过此标识符进行通信
消息队列
提供一个进程向另一个进程发送有类型(特殊标记)的数据块(链表结构),数据块的长度是有限制的(又宏 MSGMAX定义),系统中所有队列所包含的全部数据块的总长度也有上限值
消息队列独立于发送与接收进程而存在,如果没有在进程中删除消息队列,即使所有使用消息队列的进程都退出了,该消息队列与消息队列的内容都不会被删除,他们余留在系统中直至有某个进程调用msgrcv()读消息或者msgctl()删除消息,或者由用户执行ipcrm命令显式的删除消息队列,这种行为与普通管道不同,当最后一个访问管道的进程终止时,管道就会被完全删除,和FIFO又有所不同,虽然当最后一个引用FIFO的进程终止时,其文件名依然存在在系统中,直至显式的删除,但是留在FIFO中的数据会在进程终止时全部删除。
struct msqid_ds //内核为每个消息队列设置一个shmid_ds的结构管理消息队列
{
struct ipc_perm msg_perm;//所有者和权限标识
time_t msg_stime;//最后一次发送消息的时间
time_t msg_rtime;//最后一次接收消息的时间
time_t msg_ctime;//最后改变时间
unsigned long _msg_cbytes;//队列中当前的数据字节数
msgqnum_t msh_qnum;//队列中当前消息数
msglen_t msg_qbytes;//队列允许的最大字节数
pid_t msg_lspid;//最后发送消息的进程的pid
pid_t msg_lrpid;//最后接收消息的pid
}
消息队列的优点:
1、在消息队列机制中,双方是通过消息来通信的,无需花费精力从字节流中解析出完整的消息
2、每条消息都有type字段,消息的读取进程可以通过type字段选择自己感兴趣的消息,也可以根据type字段实现消息的优先级读取,不一定要按照消息的生成顺序依次读取
#include //创建或打开消息队列
int msgget(key_t key,int msgflg)
//key 为整形变量,相应的IPC标识符ID
//msgflg 不同的控制逻辑如下:
当无特殊标记时,key不存在(出错返回-1)key已存在(成功返回0,获取已有标识符)
IPC_CREAT,key不存在(成功返回0,创建新标识符)key已存在(成功返回0,获取已有标识符)
IPC_CREAT | IPC_EXCL,key不存在(成功返回0,创建新标识符)key已存在(出错返回-1)
key值的创建:
fotk()_____把导出的pathname的信息 与ID的低8位组合成一个整数key_t键
#include
#include
key_t ftok(const char* pathname,int proj_id);
//查看消息队列个数上限
ipcs -q -l
//查看消息队列指令
ipcs -q
//删除消息队列
ipcrm -q msqid
//发送消息
#include
#include
#include
int msgsnd(int msqid,const char *msqp,size_t msgsz,int msgflg)
//msqid 是由msgget返回的标识符ID
//msqp 指向用户定义的缓冲区,它的第一个消息必须是一个指定消息类型的long型,后面跟消息文本内容
struct msgbuf
{
long mtype;//消息类型 ,必须大于0
char mtext[1]; //消息体,任意结构
}
//msgsz 指定了mtest字段中包含的字节数
//接收消息
ssize_t msgrcv(int msqip,void *msqp,size_t msgsz,long msgtyp,int msgflg)
//msgtyp 一个长整数,若值为0 ,获取队列中第一个可用消息《先入先出》,若值大于0,获取具有相同类型的第一个消息《消息队列中第一条mtype值等于msgtyp的消息取出来》,若值小于0,获取消息队列中mtype最小的《优先级消息队列》
//控制消息队列
int msgctl(int msqid, int cmd,struct msqid_ds* buf)
//cmd 要采取的动作
1、IPC_STAT 将内核所管理的消息队列的当前属性值复制到buf中
2、IPC_SET 如果有足够限权,就把消息队列当前属性的值设置为buf各成员的值
3、IPC_RMID 删除消息队列