• linux消息队列应用编程


      消息队列:

            消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法
            每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值
            消息队列也有管道一样的不足,就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI)
      对比管道和消息:
      管道:流管道        消息:有边界
      先进先出              可以后进入、先出来
      消息大小三大限制
      cat /proc/sys/kernel/msgmax最大消息长度限制
      cat /proc/sys/kernel/msgmnb消息队列总的字节数
      cat /proc/sys/kernel/msgmni消息条目数

      IPC对象数据结构
          内核为每个IPC对象维护一个数据结构
            struct ipc_perm {
                key_t __key;       /* Key supplied to xxxget(2) */
                uid_t uid;         /* Effective UID of owner */
                gid_t gid;         /* Effective GID of owner */
                uid_t cuid;        /* Effective UID of creator */
                gid_t cgid;        /* Effective GID of creator */
                unsigned short mode;   /* Permissions */
                unsigned short __seq;  /* Sequence number */
            };

            struct msqid_ds {
                struct ipc_perm msg_perm;     /* Ownership and permissions */
                time_t            msg_stime;    /* Time of last msgsnd(2) */
                time_t            msg_rtime;    /* Time of last msgrcv(2) */
                time_t            msg_ctime;    /* Time of last change */
                unsigned long   __msg_cbytes; /* Current number of bytes in queue (nonstandard) */
                msgqnum_t        msg_qnum;     /* Current number of messages in queue */
                msglen_t        msg_qbytes;   /* Maximum number of bytes allowed in queue */
                pid_t            msg_lspid;    /* PID of last msgsnd(2) */
                pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
            };

    消息队列在内核中的表:

      

    消息队列函数:
        #include <sys/types.h>
        #include <sys/ipc.h>
        #include <sys/msg.h>
        intmsgget(key_t key, intmsgflg);
        intmsgctl(intmsqid, intcmd, structmsqid_ds *buf);
        intmsgsnd(intmsqid, const void *msgp, size_tmsgsz, intmsgflg);
        ssize_tmsgrcv(intmsqid, void *msgp, size_tmsgsz, long msgtyp, intmsgflg);

      msgget函数
            功能:用来创建和访问一个消息队列
            原型:intmsgget(key_t key, intmsgflg);
            参数:
                  key: 某个消息队列的名字
                  msgflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
                返回值:成功返回一个非负整数,即该消息队列的标识码;失败返回-1

         msgget函数参数关系图:

         

       msgctl函数
            功能:消息队列的控制函数
            原型:intmsgctl(intmsqid, intcmd, structmsqid_ds *buf);
            参数:
                msqid: 由msgget函数返回的消息队列标识码
                cmd:是将要采取的动作,(有三个可取值)
            返回值:成功返回0,失败返回-1
            cmd:将要采取的动作(有三个可取值),分别如下:

         

    消息队列的发送和接受:

      msgsnd函数
            功能:把一条消息添加到消息队列中
            原型:intmsgsnd(intmsqid, const void *msgp, size_tmsgsz, intmsgflg);
            参数:
                msgid: 由msgget函数返回的消息队列标识码
                msgp:是一个指针,指针指向准备发送的消息,
                msgsz:是msgp指向的消息长度,这个长度不含保存消息类型的那个long int长整型
                msgflg:控制着当前消息队列满或到达系统上限时将要发生的事情
            返回值:成功返回0;失败返回-1
            msgflg=IPC_NOWAIT表示队列满不等待,返回EAGAIN错误。
            消息结构在两方面受到制约。首先,它必须小于系统规定的上限值;其次,它必须以一个long int长整数开始,接收者函数将利用这个长整数确定消息的类型
            消息结构参考形式如下:
                        structmsgbuf {
                            long  mtype;
                            char mtext[100];
                        }

        msgrcv函数
            功能:是从一个消息队列接收消息
            原型:ssize_tmsgrcv(intmsqid, void *msgp, size_tmsgsz, long msgtyp, intmsgflg);
            参数:
                msgid: 由msgget函数返回的消息队列标识码
                msgp:是一个指针,指针指向准备接收的消息,
                msgsz:是msgp指向的消息长度,这个长度不含保存消息类型的那个long int长整型
                msgtype:它可以实现接收优先级的简单形式
                msgflg:控制着队列中没有相应类型的消息可供接收时将要发生的事
            返回值:成功返回实际放到接收缓冲区里去的字符个数,失败返回-1
            msgtype=0返回队列第一条信息
            msgtype>0返回队列第一条类型等于msgtype的消息 
            msgtype<0返回队列第一条类型小于等于msgtype绝对值的消息,并且是满足条件的消息类型最小的消息
            
            msgflg=IPC_NOWAIT,队列没有可读消息不等待,返回ENOMSG错误。
            msgflg=MSG_NOERROR,消息大小超过msgsz时被截断
            msgtype>0且msgflg=MSG_EXCEPT,接收类型不等于msgtype的第一条消息。

    消息队列综合api使用:

      同一个进程,使用消息队列代码示例:

      

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include <sys/types.h>
     4 #include <sys/ipc.h>
     5 #include <sys/msg.h>
     6 #include<errno.h>
     7 #include<string.h>
     8 #include <sys/types.h>
     9 #include <unistd.h>
    10 struct msg_buf
    11 {
    12     long mtype;
    13     char data[255];
    14 };
    15 
    16 /* 注意long 和int在32bit 和 64bit系统之下是不一样的
    17 structmsg_buf
    18 {
    19     long mtype;
    20     char data[255];
    21 };
    22 */
    23 
    24 int main()
    25 {
    26     key_t key;
    27     int msgid;
    28     int ret;
    29     struct msg_buf    msgbuf;
    30     int    msgtype =  getpid();
    31     //系统建立IPC通讯 (消息队列、信号量和共享内存) 时必须指定一个ID值。通常情况下,该id值通过ftok函数得到。
    32     key=ftok("./msgfile",'a');
    33     printf("key =[%x]
    ",key);
    34 
    35     printf("sizeof(long):%ld, sizeof(int):%d 
    ", sizeof(long), sizeof(int));
    36     //用来创建和访问一个消息队列
    37     msgid=msgget(key, IPC_CREAT |IPC_EXCL|0666); //通过文件对应
    38 
    39     if(msgid==-1)
    40     {
    41         if (errno == EEXIST)
    42         {
    43             printf("EEXIST:.....
    ");
    44             key=ftok("./msgfile",'a');
    45             msgid=msgget(key, IPC_CREAT|0666); //通过文件对应
    46         }
    47         else
    48         {
    49             printf("create error
    ");
    50             perror("msget: 
    ");
    51             return -1;
    52         }
    53         
    54     }
    55     printf("msgid:%d 
    ", msgid);
    56     
    57     msgbuf.mtype = msgtype; //        getpid();
    58 
    59     printf("getpid(): %d 
    ", getpid());
    60     strcpy(msgbuf.data,"hello world!");
    61     //把一条data消息添加到消息队列,IPC_NOWAIT表示队列满不等待,返回EAGAIN错误
    62     ret = msgsnd(msgid,&msgbuf, sizeof(msgbuf.data), IPC_NOWAIT);
    63     if(ret==-1)
    64     {
    65         printf("send message err
    ");
    66         perror("senderr");
    67         return -1;
    68     }
    69     sleep(1);
    70 
    71     memset(&msgbuf,0,sizeof(msgbuf));
    72     //是从一个消息队列接收消息,队列没有可读消息不等待,返回ENOMSG错误
    73     ret=msgrcv(msgid, &msgbuf, sizeof(msgbuf.data), msgtype, IPC_NOWAIT);
    74     if(ret==-1)
    75     {
    76         printf("recv message err
    ");
    77         perror("dd");
    78         return -1;
    79     }
    80     printf("recvmsg =[%s]
    ",msgbuf.data);
    81     return 0;
    82 }

    编译执行程序,结果如下所示:

    消息队列项目开发案例(消息队列实现回射客户/服务器)示意:

  • 相关阅读:
    数组名和指针区别(还有数组退化等)
    无法从“const char *”转换为“char *”
    c语言数组初始化问题
    c语言实现atoi和itoa函数。
    不使用临时变量交换两个整数
    hdu 1282回文数猜想
    Android仿WIN8系统磁贴点击下沉倾斜效果
    Android Studio使用心得
    处理json中影响解析的多余引號
    我也来开发2048之主界面设计
  • 原文地址:https://www.cnblogs.com/liunianshiwei/p/6112024.html
Copyright © 2020-2023  润新知