• IPC通信:Posix消息队列


    IPC通信:Posix消息队列
    
     消息队列可以认为是一个链表。进程(线程)可以往里写消息,也可以从里面取出消息。一个进程可以往某个消息队列里写消息,然后终止,另一个进程随时可以从消息队列里取走这些消息。这里也说明了,消息队列具有随内核的持续性,也就是系统不重启,消息队列永久存在。
    
    创建(并打开)、关闭、删除一个消息队列
    
    
     1 #include <stdio.h>  
     2 #include <stdlib.h> 
     3 #include <mqueue.h>   //头文件
     4 #include <sys/types.h>  
     5 #include <sys/stat.h>  
     6 #include <unistd.h>  
     7 #include <fcntl.h>  
     8 #include <errno.h>   
     9 
    10 #define MQ_NAME ("/tmp")  
    11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag  
    12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限  
    13 
    14 int main()  
    15 
    16 {  
    17     mqd_t posixmq;  
    18     int rc = 0;  
    19 
    20     /*  
    21     函数说明:函数创建或打开一个消息队列  
    22     返回值:成功返回消息队列描述符,失败返回-1,错误原因存于errno中  
    23     */ 
    24     posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);  
    25 
    26     if(-1 == posixmq)  
    27     {  
    28         perror("创建MQ失败");  
    29         exit(1);  
    30     }  
    31 
    32     /*  
    33     函数说明:关闭一个打开的消息队列,表示本进程不再对该消息队列读写  
    34     返回值:成功返回0,失败返回-1,错误原因存于errno中  
    35     */ 
    36     rc = mq_close(posixmq);  
    37     if(0 != rc)  
    38     {  
    39         perror("关闭失败");  
    40         exit(1);  
    41     }  
    42 
    43     /*  
    44     函数说明:删除一个消息队列,好比删除一个文件,其他进程再也无法访问  
    45     返回值:成功返回0,失败返回-1,错误原因存于errno中  
    46     */
    47     rc = mq_unlink(MQ_NAME);  
    48     if(0 != rc)  
    49     {  
    50         perror("删除失败");  
    51         exit(1);  
    52     }  
    53 
    54     return 0;  
    55 } 
    
    编译并执行:
    
     1 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c
     2 /tmp/ccZ9cTxo.o: In function `main':
     3 crtmq.c:(.text+0x31): undefined reference to `mq_open'
     4 crtmq.c:(.text+0x60): undefined reference to `mq_close'
     5 crtmq.c:(.text+0x8f): undefined reference to `mq_unlink'
     6 collect2: ld returned 1 exit status
     7 因为mq_XXX()函数不是标准库函数,链接时需要指定;库-lrt;
     8 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c -lrt
     9 
    10 root@linux:/mnt/hgfs/C_libary# ./crtmq
    11 最后程序并没有删除消息队列(消息队列有随内核持续性),如再次执行该程序则会给出错误信息: 
    12 root@linux:/mnt/hgfs/C_libary# ./crtmq 
    13 创建MQ失败: File  exit(0)
    
    编译这个程序需要注意几点:
    
    1消息队列的名字最好使用“/”打头,并且只有一个“/”的名字。否则可能出现移植性问题;(还需保证在根目录有写权限,为了方便我在root权限下测试)
    2、创建成功的消息队列不一定能看到,使用一些方法也可以看到,本文不做介绍;
    
      消息队列的名字有如此规定,引用《UNIX网络编程 卷2》的相关描述: mq_open,sem_open,shm_open这三个函数的第一个参数是
    一个IPC名字,它可能是某个文件系统中的一个真正存在的路径名,也可能不是。Posix.1是这样描述Posix IPC名字的。 
    1)它必须符合已有的路径名规则(最多由PATH_MAX个字节构成,包括结尾的空字节) 
    2)如果它以斜杠开头,那么对这些函数的不同调用将访问同一个队列,否则效果取决于实现(也就是效果没有标准化) 
    3)名字中的额外的斜杠符的解释由实现定义(同样是没有标准化) 因此,为便于移植起见,Posix IPC名字必须以一个斜杠打头,并且不能再包含任何其他斜杠符。
    
    
    IPC通信:Posix消息队列读,写
    
    创建消息队列的程序:
    
    
     1 #include <stdio.h>  
     2 #include <stdlib.h> 
     3 #include <mqueue.h>   //头文件
     4 #include <sys/types.h>  
     5 #include <sys/stat.h>  
     6 #include <unistd.h>  
     7 #include <fcntl.h>  
     8 #include <errno.h>   
     9 
    10 #define MQ_NAME ("/tmp")  
    11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag  
    12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限  
    13 
    14 int main()  
    15 
    16 {  
    17     mqd_t posixmq;  
    18     int rc = 0;  
    19 
    20     /*  
    21     函数说明:函数创建或打开一个消息队列  
    22     返回值:成功返回消息队列描述符,失败返回-1,错误原因存于errno中  
    23     */ 
    24     posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);  
    25 
    26     if(-1 == posixmq)  
    27     {  
    28         perror("创建MQ失败");  
    29         exit(1);  
    30     }  
    31 
    32     /*  
    33     函数说明:关闭一个打开的消息队列,表示本进程不再对该消息队列读写  
    34     返回值:成功返回0,失败返回-1,错误原因存于errno中  
    35     */ 
    36     rc = mq_close(posixmq);  
    37     if(0 != rc)  
    38     {  
    39         perror("关闭失败");  
    40         exit(1);  
    41     }  
    42 
    43 #if 0
    44     /*  
    45     函数说明:删除一个消息队列,好比删除一个文件,其他进程再也无法访问  
    46     返回值:成功返回0,失败返回-1,错误原因存于errno中  
    47     */
    48     rc = mq_unlink(MQ_NAME);  
    49     if(0 != rc)  
    50     {  
    51         perror("删除失败");  
    52         exit(1);  
    53     }  
    54 
    55     return 0;
    56 #endif  
    57 } 
    
    编译并执行:
    
    1 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c -lrt
    2 root@linux:/mnt/hgfs/C_libary# ./crtmq
    3 程序并没有删除消息队列(消息队列有随内核持续性),如再次执行该程序则会给出错误信息: 
    4 root@linux:/mnt/hgfs/C_libary# ./crtmq 
    5 创建MQ失败: File  exit(0)
    向消息队列写消息的程序:
    
    
    消息队列的读写主要使用下面两个函数: 
    /*头文件*/
    #include <mqueue.h>  
    
    /*返回:若成功则为消息中字节数,若出错则为-1 */ 
    int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio); 
    
    /*返回:若成功则为0, 若出错则为-1*/ 
    ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio);  
    
    /*消息队列属性结构体*/
    struct mq_attr { 
       long mq_flags;       /* Flags: 0 or O_NONBLOCK */ 
       long mq_maxmsg;      /* Max. # of messages on queue */ 
       long mq_msgsize;     /* Max. message size (bytes) */ 
       long mq_curmsgs;     /* # of messages currently in queue */ 
    };
    
     1 #include <stdio.h>  
     2 #include <stdlib.h>  
     3 #include <mqueue.h>  
     4 #include <sys/types.h>  
     5 #include <sys/stat.h>  
     6 #include <unistd.h>  
     7 #include <fcntl.h>  
     8 #include <errno.h>  
     9    
    10 /*向消息队列发送消息,消息队列名及发送的信息通过参数传递*/ 
    11 int main(int argc, char *argv[])  
    12 {  
    13     mqd_t mqd;  
    14     char *ptr;  
    15     size_t len;  
    16     unsigned int prio;  
    17     int rc;  
    18 
    19     if(argc != 4)  
    20     {  
    21         printf("Usage: sendmq <name> <bytes> <priority>
    ");  
    22         exit(1);  
    23     }  
    24 
    25     len = atoi(argv[2]);  
    26     prio = atoi(argv[3]);    
    27 
    28     //只写模式找开消息队列  
    29     mqd = mq_open(argv[1], O_WRONLY);  
    30     if(-1 == mqd)  
    31     {  
    32         perror("打开消息队列失败");  
    33         exit(1);  
    34     }  
    35 
    36     // 动态申请一块内存  
    37     ptr = (char *) calloc(len, sizeof(char));  
    38     if(NULL == ptr)  
    39     {  
    40         perror("申请内存失败");  
    41         mq_close(mqd);  
    42         exit(1);  
    43     }  
    44    
    45     /*向消息队列写入消息,如消息队列满则阻塞,直到消息队列有空闲时再写入*/ 
    46     rc = mq_send(mqd, ptr, len, prio);  
    47     if(rc < 0)  
    48     {  
    49         perror("写入消息队列失败");  
    50         mq_close(mqd);  
    51         exit(1);  
    52     }     
    53 
    54     // 释放内存  
    55     free(ptr);  
    56     return 0;  
    57 } 
    
    编译并执行:
    
    1 root@linux:/mnt/hgfs/C_libary# gcc -o sendmq sendmq.c -lrt
    2 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 15
    3 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 16
    4 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 17
    5 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 18
      上面先后向消息队列“/tmp”写入了四条消息,因为先前创建的消息队列只允许存放3条消息,本次第四次写入时程序会阻塞。直到有另外进程从消息队列取走消息后本次写入才成功返回。
    
    读消息队列:
    
    
    #include <stdio.h>  
    #include <stdlib.h>  
    #include <mqueue.h>  
    #include <sys/types.h>  
    #include <sys/stat.h>  
    #include <unistd.h>  
    #include <fcntl.h>  
    #include <errno.h>  
    
    /*读取某消息队列,消息队列名通过参数传递*/ 
    int main(int argc, char *argv[])  
    {  
        mqd_t mqd;  
        struct mq_attr attr;  
        char *ptr;  
        unsigned int prio;  
        size_t n;  
        int rc;  
    
        if(argc != 2)  
        {  
            printf("Usage: readmq <name>
    ");  
            exit(1);  
        }  
    
        /*只读模式打开消息队列*/ 
        mqd = mq_open(argv[1], O_RDONLY);  
        if(mqd < 0)  
        {  
            perror("打开消息队列失败");  
            exit(1);  
        }     
    
        // 取得消息队列属性,根据mq_msgsize动态申请内存  
        rc = mq_getattr(mqd, &attr);  
        if(rc < 0)  
        {  
            perror("取得消息队列属性失败");  
            exit(1);  
        }  
    
        /*动态申请保证能存放单条消息的内存*/ 
        ptr = calloc(attr.mq_msgsize, sizeof(char));  
        if(NULL == ptr)  
        {  
            printf("动态申请内存失败
    ");  
            mq_close(mqd);  
            exit(1);  
        }     
    
        /*接收一条消息*/ 
        n = mq_receive(mqd, ptr, attr.mq_msgsize, &prio);  
        if(n < 0)  
        {  
            perror("读取失败");  
            mq_close(mqd);  
            free(ptr);  
            exit(1);  
        }  
        
        printf("读取 %ld 字节
      优先级为 %u
    ", (long)n, prio);     
        return 0;  
    } 
    
    编译并执行:
    
    
     1 root@linux:/mnt/hgfs/C_libary# vi readmq.c
     2 root@linux:/mnt/hgfs/C_libary# vi readmq.c
     3 root@linux:/mnt/hgfs/C_libary# gcc -o readmq readmq.c -lrt
     4 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
     5 读取 30 字节
     6   优先级为 18
     7 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
     8 读取 30 字节
     9   优先级为 17
    10 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
    11 读取 30 字节
    12   优先级为 16
    13 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
    14 读取 30 字节
    15     优先级为 15
    16 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
    
      程序执行五次,第一次执行完,先前阻塞在写处的程序成功返回。第五次执行,因为消息队列已经为空,程序阻塞。直到另外的进程向消息队列写入一条消息。另外,还可以看出Posix消息队列每次读出的都是消息队列中优先级最高的消息。
    
    IPC通信:Posix消息队列的属性设置
    
    
    Posix消息队列的属性使用如下结构存放:
    struct mq_attr  
    {  
        long mq_flags; /*阻塞标志位,0为非阻塞(O_NONBLOCK)*/ 
        long mq_maxmsg; /*队列所允许的最大消息条数*/ 
        long mq_msgsize; /*每条消息的最大字节数*/ 
        long mq_curmsgs; /*队列当前的消息条数*/ 
    }; 
    队列可以在创建时由mq_open()函数的第四个参数指定mq_maxmsg,mq_msgsize。 如创建时没有指定则使用默认值,一旦创建,则不可再改变。
    队列可以在创建后由mq_setattr()函数设置mq_flags 
    
    #include <mqueue.h>  
    
    /*取得消息队列属性,放到mqstat地fh*/ 
    int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat);  
    
    /*设置消息队列属性,设置值由mqstat提供,原先值写入omqstat*/ 
    int mq_setattr(mqd_t mqdes, const struct mq_attr *mqstat, struct mq_attr *omqstat);  
    
    均返回:若成功则为0,若出错为-1 
    
    程序获取和设置消息队列的默认属性:
    1 #include <stdio.h>  
     2 #include <stdlib.h>  
     3 #include <mqueue.h>  
     4 #include <sys/types.h>  
     5 #include <sys/stat.h>  
     6 #include <unistd.h>  
     7 #include <fcntl.h>  
     8 #include <errno.h>  
     9    
    10 #define MQ_NAME ("/tmp")  
    11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag  
    12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限  
    13    
    14 int main()  
    15 {  
    16     mqd_t posixmq;  
    17     int rc = 0;  
    18    
    19     struct mq_attr mqattr;  
    20    
    21     // 创建默认属性的消息队列  
    22     posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);  
    23     if(-1 == posixmq)  
    24     {  
    25         perror("创建MQ失败");  
    26         exit(1);  
    27     }  
    28        
    29     // 获取消息队列的默认属性  
    30     rc = mq_getattr(posixmq, &mqattr);  
    31     if(-1 == rc)  
    32     {  
    33         perror("获取消息队列属性失败");  
    34         exit(1);  
    35     }  
    36 
    37     printf("队列阻塞标志位:%ld
    ", mqattr.mq_flags);  
    38     printf("队列允许最大消息数:%ld
    ", mqattr.mq_maxmsg);  
    39     printf("队列消息最大字节数:%ld
    ", mqattr.mq_msgsize);  
    40     printf("队列当前消息条数:%ld
    ", mqattr.mq_curmsgs);  
    41    
    42     rc = mq_close(posixmq);  
    43     if(0 != rc)  
    44     {  
    45         perror("关闭失败");  
    46         exit(1);  
    47     }  
    48    
    49     rc = mq_unlink(MQ_NAME);  
    50     if(0 != rc)  
    51     {  
    52         perror("删除失败");  
    53         exit(1);  
    54     }     
    55     return 0;  
    56 } 
    
    编译并执行:
    1 root@linux:/mnt/hgfs/C_libary# gcc -o attrmq attrmq.c -lrt
    2 root@linux:/mnt/hgfs/C_libary# ./attrmq
    3 队列阻塞标志位:0
    4 队列允许最大消息数:10
    5 队列消息最大字节数:8192
    6 队列当前消息条数:0
    7 root@linux:/mnt/hgfs/C_libary# 
    
    设置消息队列的属性:
    
    
     1 #include <stdio.h>  
     2 #include <stdlib.h>  
     3 #include <mqueue.h>  
     4 #include <sys/types.h>  
     5 #include <sys/stat.h>  
     6 #include <unistd.h>  
     7 #include <fcntl.h>  
     8 #include <errno.h>  
     9    
    10 #define MQ_NAME ("/tmp")  
    11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag  
    12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限  
    13    
    14 int main()  
    15 {  
    16     mqd_t posixmq;  
    17     int rc = 0;  
    18    
    19     struct mq_attr mqattr;  
    20   
    21     // 创建默认属性的消息队列  
    22     mqattr.mq_maxmsg = 5; // 注意不能超过系统最大限制  
    23     mqattr.mq_msgsize = 8192;  
    24     //posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);  
    25     posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, &mqattr);  
    26 
    27     if(-1 == posixmq)  
    28     {  
    29         perror("创建MQ失败");  
    30         exit(1);  
    31     }  
    32     
    33     mqattr.mq_flags = 0;  
    34     mq_setattr(posixmq, &mqattr, NULL);// mq_setattr()只关注mq_flags,adw  
    35        
    36     // 获取消息队列的属性  
    37     rc = mq_getattr(posixmq, &mqattr);  
    38     if(-1 == rc)  
    39     {  
    40         perror("获取消息队列属性失败");  
    41         exit(1);  
    42     }  
    43 
    44     printf("队列阻塞标志位:%ld
    ", mqattr.mq_flags);  
    45     printf("队列允许最大消息数:%ld
    ", mqattr.mq_maxmsg);  
    46     printf("队列消息最大字节数:%ld
    ", mqattr.mq_msgsize);  
    47     printf("队列当前消息条数:%ld
    ", mqattr.mq_curmsgs);  
    48    
    49     rc = mq_close(posixmq);  
    50     if(0 != rc)  
    51     {  
    52         perror("关闭失败");  
    53         exit(1);  
    54     }    
    55 
    56     rc = mq_unlink(MQ_NAME);  
    57     if(0 != rc)  
    58     {  
    59         perror("删除失败");  
    60         exit(1);  
    61     }
    62          
    63     return 0;  
    64 } 
    复制代码
    编译运行:
    
    复制代码
    1 root@linux:/mnt/hgfs/C_libary# gcc -o setattrmq setattrmq.c -lrt
    2 root@linux:/mnt/hgfs/C_libary# ./setattrmq
    3 队列阻塞标志位:0
    4 队列允许最大消息数:5
    5 队列消息最大字节数:8192
    6 队列当前消息条数:0
    本文转自:http://blog.csdn.net/liuhongxiangm/article/details/8716232
  • 相关阅读:
    UVA 465 Overflow (浮点数的优势)
    UVA 424 Integer Inquiry (大数相加问题)
    UVA 10494 If We Were a Child Again(大数与整型相除取整和取余)
    粘一个在UVA和ZOJ都能AC但POJ WR的代码
    UVA 340 MasterMind Hints
    UVA10815 Andy's First Dictionary
    MSComm写串口通信驱动步骤
    UVA 10106 Product (大数相乘问题)
    实现工具栏中添加的组合框接收回车消息
    UVA 10420 List of Conquests
  • 原文地址:https://www.cnblogs.com/leijiangtao/p/4083893.html
Copyright © 2020-2023  润新知