博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
IPC(一)之消息队列
阅读量:6064 次
发布时间:2019-06-20

本文共 3766 字,大约阅读时间需要 12 分钟。

hot3.png

    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即可。
二。消息队列(include <sys/msg.h>)
    消息队列在内核地址空间内被描述为一个链表,每个消息队列都有唯一的一个消息队列标识号。
系统为所有消息队列维护一个msgque链表,链表中的每个节点都有一个指向一个msqid_ds结构的指针,
该结构完整的描述了一个消息队列。
            time_t msg_stime;     };
    消息队列的相关函数:
    int msgget(key_t key,int flag);
        功能:创建或得到一个消息队列标识符
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\n",buf.text);     }

转载于:https://my.oschina.net/nalenwind/blog/120349

你可能感兴趣的文章
初始if..else 条件语句
查看>>
python FileError
查看>>
《深入理解计算机系统》第一章学习笔记
查看>>
Rocket - util - MultiWidthFifo
查看>>
jQuery fullPage 全屏滚动
查看>>
关于C#虚函数和构造函数的一点理解
查看>>
::c++的样子,
查看>>
fuck,两个地方,
查看>>
郁闷,蛋疼的S3C2416 ,哥狠狠的被2416 手册 暗算了一把
查看>>
对象属性访问的总结
查看>>
深搜广搜
查看>>
VisualStudio自定义代码段_方法二
查看>>
WC2008游览计划(BZOJ2595)
查看>>
消息队列
查看>>
《Android深度探索》第六章心得体会
查看>>
嵌入式服务器jetty,让你更快开发web
查看>>
【原创】基于ZYNQ7000的交叉编译工具链Qt+OpenCV+ffmpeg等库支持总结(二)
查看>>
【HDOJ】1493 QQpet exploratory park
查看>>
【HDOJ】3553 Just a String
查看>>
一共81个,开源大数据处理工具汇总(上)(转)
查看>>