❲知多少❳IPC之消息队列
Posted VanillaOpenResty开发
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了❲知多少❳IPC之消息队列相关的知识,希望对你有一定的参考价值。
来源:纳兰清风
原文地址:http://my.oschina.net/nalenwind/blog/120349
System V IPC包括三种进程间通信方式,即消息队列,信号量集和共享内存。
一、IPC对象
IPC对象是进程间通信的实体,一旦被创建便一直存在于内存中,通过一个称为键值key_t的数
据结构来全局唯一标识。但是对IPC对象的访问并不是通过键值,而是通过标识符进行的。不同的键
值产生不同的IPC标识符,而不同的进程通过同一个键值打开IPC对象时产生的IPC标识符是相同的。
关于键值的产生可以使用ftok函数,原型如下:
key_t ftok(const char* filename,int proj_id) //include <sys/ipc.h>
filename:指定文件,该文件必须存在且可取
proj_id:计划代号
成功返回key_t键值,失败返回-1 //详细说明见联机手册
使用同一个文件和相同的proj_id生成的键值是相同的,即filename+proj_id---->key_t是一个一对
一的函数。
下一阶段,使用IPC键值打开一个IPC对象返回IPC标识符可以使用semget,shmget,msgget这三个
函数。详细说明见下文。
系统为每一个IPC对象保存了一个ipc_perm结构体,该结构说明了IPC对象的权限和所有者,并确
定了一个IPC操作是否可以访问该IPC对象。
struct ipc_perm{ key_t key; //此IPC对象的键值 uid_t uid; //此IPC对象用户ID gid_t gid; //此IPC对象组ID uid_t cuid; //此IPC对象创建进程的有效用户ID gid_t cgid; //此IPC对象创建进程的有效组ID mode_t mode; //此IPC对象的读写权限 ulong_t seq; //IPC对象的序列号 };
当使用XXXget函数创建IPC对象的时候,会初始化ipc_perm结构体,将数据成员赋值。其中mode
参数会根据XXXget函数中的flag参数设置模式,若访问一个已存在的IPC对象,则flag设置为0即可。
struct msqid_ds{ struct ipc_perm msg_perm; struct msg* msg_first; struct msg* msg_last; time_t msg_stime; time_t msg_rtime; time_t msg_ctime; ushort msg_cbytes; ushort msg_qnum; ushort msg_qbytes; ushort msg_lspid; ushort msg_lrpid; };
key:当被指定为IPC_PRIVATE即0时,会由系统设置key创建新的消息队列
当key大于0时,视参数flag来确定操作
flag:IPC_CREAT:如果这个队列在内核中不存在,则创建它。
IPC_EXCL:当与IPC_CREAT一起使用时,如果这个队列已存在,则创建失败。
返回:成功返回IPC对象标识符,失败返回-1
如果IPC_CREAT单独使用,semget()为一个新创建的消息队列返回标识号,或者返回具有相同
键值的已存在队列的标识号。如果IPC_EXCL与IPC_CREAT一起使用,要么创建一个新的队列,
要么对已存在的队列返回-1。IPC_EXCL单独是没有用的,当与IPC_CREAT结合起来使用时,可
以保证新创建队列的打开和存取。
同时flag为模式标志参数,使用时需要需要与存取权限进行位或(|)运算。
实例代码如下:
int id=msgget(IPC_PRIVATE,IPC_CREAT|0600);
int msgctl(int msgqid,int cmd,struct msqid_ds* buff)
功能:用于对消息队列对象的控制,
msqid:要操作的消息队列标识符
cmd:要执行的操作,可取值包括:
IPC_STAT:获得msqid的消息队列头数据到buff中
IPC_SET:设置消息队列的属性,要设置的属性存于buff中,可设置的属性如下:
msg_perm.uid,msg_perm.gid,msg_perm.mode以及msg_qbytes
返回:成功返回0,失败返回-1.
实例代码:
msqid_id buff;
msgctl(id,IPC_STAT,&buff);
int msgsnd(int msqid,const void* msgp,size_t msgsz,int msgflg)
功能:将msgp消息写入标识符为msqid的消息队列
msqid:要操作的消息队列标识符
msgp:发送给队列的消息,可以是任何类型的结构,但第一个字段必须为long类型,标明此发
送消息的类型,msgrcv根据此接收消息。msgp的参照格式如下:
struct msg{
long type; //大于0,消息类型
<Type> msg_text;//正文
}msgp;
<Type>是指这里可以是任意类型的结构数据
msgsz:消息正文的大小,不包含消息类型的4字节,即sizeof(msg)-sizeof(long)
msgflg:设定执行的详细操作,可取值如下:
IPC_NOWAIT:当消息队列满的时候,函数不等待,直接返回
IPC_NOERROR:发送消息大于size字节,则把消息截断。
返回:成功返回0,失败返回-1.
ssize_t msgrcv(int msqid,void* msgp,size_t msgsz,long msgtyp,int msgflg)
功能:从标识符为msqid的消息队列读取消息并存于msgp,读取后的消息将从队列中删除
msqid:要操作的消息队列标识符
msgp: 存放消息的结构体,结构体类型要与msgsnd发送的类型相同
msgsz:要接受消息的大小,不包含消息类型占用的4字节
msgtyp:=0:接收第一个消息
>0:接收类型等于msgtyp的第一个消息
<0:接收类型小于或等于msgtyp绝对值的第一个消息
msgflg:0:阻塞时接收消息,没有符合类型的消息则一直阻塞等待
IPC_NOWAIT:没有可取的消息时,函数返回ENOMSG错误消息
IPC_EXCEPT:与msgtyp配合使用,返回队列中第一个类型部位msgtyp的消息
IPC_NOERROR:消息截断
实例代码如下:
typedef struct msg{ long type; char text[10]; }MSG; int sendmsg(const char* filename,int proj_id) { key_t key=ftok(filename,proj_id); int id=msgget(key,IPC_CREAT|0600); MSG buf; buf.type=1; strcpy(buf.text,"hello"); int sendlength=sizeof(MSG)-sizeof(long); msgsnd(id,&buf,sendlength,0); } int recvmsg(const char* filename,int proj_id) { key_t key=ftok(filename,proj_id); int id=msgget(key,IPC_CREAT|0600); MSG buf; int recvlength=sizeof(MSG)-sizeof(long); msgrcv(id,&buf,recvlength,1,0); printf("%s ",buf.text); }
Vanilla社区发起⦗晨读计划⦘,每天坚持积累一点,今天的努力至少让我们比昨天更进一步。
⦗晨读计划⦘ 期待你的加入... ...
晨读计划
2016/06/20
以上是关于❲知多少❳IPC之消息队列的主要内容,如果未能解决你的问题,请参考以下文章