❲知多少❳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社区发起⦗晨读计划⦘,每天坚持积累一点,今天的努力至少让我们比昨天更进一步。

⦗晨读计划⦘ 期待你的加入... ...

Vanilla:基于OpenResty的高性能Web应用开发框架    
   
   

晨读计划

2016/06/20


以上是关于❲知多少❳IPC之消息队列的主要内容,如果未能解决你的问题,请参考以下文章

IPC之——消息队列

System V IPC 之消息队列

进程间通信(IPC)之消息队列

进程间通信(IPC)之消息队列

进程间通信——XSI IPC之消息队列

IPC之消息队列·即时通讯小程序