一、消息队列

1、消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法
2、每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值

3、消息队列与管道不同的是,消息队列是基于消息的,而管道是基于字节流的,且消息队列的读取不一定是先入先出。
4、消息队列也有管道一样的不足,就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI),这三个参数都可以查看:

simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ cat /proc/sys/kernel/msgmax
8192
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ cat /proc/sys/kernel/msgmnb
16384
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ cat /proc/sys/kernel/msgmni
1711

二、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) */
};

可以看到第一个条目就是IPC结构体,即是共有的,后面的都是消息队列所私有的成员。

四、消息队列在内核中的表示

消息队列是用链表实现的,这里需要提出的是MSGMAX指的是一条消息的纯数据大小的上限,上图是一个消息队列,则其纯数据总和不能超过MSGMNB,像这样一条消息队列,系统含有的总数不能超过MSGMNI 个。

五、msgget 和 msgctl 函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

(1)int msgget(key_t key, int msgflg);

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

创建流程如下图所示:

注意,IPC_PRIVATE 不是一个msgflg 而是一个key_t
类型,如果指定key = IPC_PRIVATE,则无论某个 key_value 这个消息队列是否存在,都会再创建一个key_value
消息队列,但他们的标识码msqid是不一样的,且指定IPC_PRIVATE 产生的是私有的消息队列。

写个小程序测试一下这个函数:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 
/*************************************************************************
    > File Name: basic.c
    > Author: Simba
    > Mail: dameng34@163.com
    > Created Time: Tue 12 Mar 2013 06:54:20 PM CST
 ************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

int main(void)
{
    int msgid;
    msgid = msgget(1234, 0666 | IPC_CREAT);
    if (msgid == -1)
        ERR_EXIT("msgget");
    printf("msgget success\n");
    msgid = msgget(1234, 0);
    printf("msgid=%d\n", msgid);

return 0;
}

程序先创建一个消息队列,名字为1234,接着打开这个消息队列,当flags = 0 表示按原来权限打开。

输出如下:

simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./msgget 
msgget success
msgid=0

我们可以使用命令ipcs  -q 查看:

simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ipcs -q

------ Message Queues --------
key         msqid     owner      perms      used-bytes   messages    
0x000004d2     0             simba       666                0                  0

可以看到0x4d2 也就是1234,msqid 为0。

(2)int msgctl(int msqid, int cmd, struct msqid_ds *buf);

功能:消息队列的控制函数
参数
msqid: 由msgget函数返回的消息队列标识码
cmd:是将要采取的动作,(有三个可取值)
返回值:成功返回0,失败返回-1

cmd 的取值如下:

我们可以通过ipcrm -q 删除一条消息队列,也可以通过msgctl 函数删除,此时设置cmd 为 IPC_RMID,如下:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 
/*************************************************************************
    > File Name: basic.c
    > Author: Simba
    > Mail: dameng34@163.com
    > Created Time: Tue 12 Mar 2013 06:54:20 PM CST
 ************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

int main(void)
{
    int msgid;
    msgid = msgget(1234, 0);
    if (msgid == -1)
        ERR_EXIT("msgget");
    printf("msgget success\n");
    printf("msgid=%d\n", msgid);

msgctl(msgid, IPC_RMID, NULL);

return 0;
}

如果我们想更改消息队列的一些参数,如权限等,可以通过msgctl 函数,cmd 取值为IPC_SET

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 
/*************************************************************************
    > File Name: basic.c
    > Author: Simba
    > Mail: dameng34@163.com
    > Created Time: Tue 12 Mar 2013 06:54:20 PM CST
 ************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

int main(void)
{
    int msgid;
    msgid = msgget(1234, 0);
    if (msgid == -1)
        ERR_EXIT("msgget");
    printf("msgget success\n");
    printf("msgid=%d\n", msgid);

struct msqid_ds buf;
    msgctl(msgid, IPC_STAT, &buf);
    printf("permission : %o\n", buf.msg_perm.mode);

sscanf("600", "%o", (unsigned int *)&buf.msg_perm.mode);
    msgctl(msgid, IPC_SET, &buf);

return 0;
}

程序先通过IPC_STAT 获取权限,再通过IPC_SET 重新设置,输出如下:

simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./msgset
msgget success
msgid=32768
permission : 666

simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ipcs -q

------ Message Queues --------
key                  msqid      owner      perms      used-bytes   messages    
0x000004d2  32768      simba      600                0                 0

注:ipcrm --删除ipc对象

ipcrm -m|-q|-s shm_id
%ipcrm -m 105

例如,我们在以0x12345678为KEY创建了一个共享内存,可以直接使用ipcrm -M 0x12345678来删除共享内存区域。

参考:

《TCP/IP详解 卷一》

《UNP》

消息队列内核结构和msgget、msgctl 函数的更多相关文章

  1. 进程间通信系列 之 消息队列函数(msgget、msgctl、msgsnd、msgrcv)及其范例

    进程间通信系列 之 概述与对比   http://blog.csdn.net/younger_china/article/details/15808685  进程间通信系列 之 共享内存及其实例   ...

  2. 消息队列函数(msgget、msgctl、msgsnd、msgrcv)及其范例

    消息队列函数由msgget.msgctl.msgsnd.msgrcv四个函数组成.下面的表格列出了这四个函数的函数原型及其具体说明. 1.   msgget函数原型 msgget(得到消息队列标识符或 ...

  3. POSIX和SYSTEM的消息队列应该注意的问题

    首先看看POSIX的代码: 1.posix_mq_server.c #include <mqueue.h>#include <sys/stat.h>#include <s ...

  4. Posix消息队列实现机制

    本文是对<Unix 网络编程 卷2:进程通信>的笔记. 引言 消息队列是进程间通信的一种方式,可是如果不理解他的实现原理,会有众多不理解之处,下面就结合本书中的例子,对posix消息队列来 ...

  5. 获取和设置消息队列的属性msgctl,删除消息队列

    消息队列的属性保存在系统维护的数据结构msqid_ds中,用户可以通过函数msgctl获取或设置消息队列的属性. int msgctl(int msqid, int cmd, struct msqid ...

  6. 消息队列通信,王明学learn

    消息队列通信 消息队列就是一个消息(一个结构)的链表.而一条消息则可看作一个记录,具有特定的格式.进程可以从中按照一定的规则添加新消息:另一些进程则可以从消息队列中读走消息. 每一个消息都是一个结构体 ...

  7. Linux进程通信之System V消息队列

    System V消息队列是Open Group定义的XSI,不属于POSIX标准.System V IPC的历史相对很早,在上个世70年代后期有贝尔实验室的分支机构开发,80年代加入System V的 ...

  8. linux 进程间消息队列通讯

    转自:http://blog.csdn.net/lifan5/article/details/7588529 http://www.cnblogs.com/kunhu/p/3608589.html 前 ...

  9. 消息队列接口API(posix 接口和 system v接口)

    消息队列 posix API 消息队列(也叫做报文队列)能够克服早期unix通信机制的一些缺点.信号这种通信方式更像\"即时\"的通信方式,它要求接受信号的进程在某个时间范围内对信 ...

随机推荐

  1. [leetcode]Copy List with Random Pointer @ Python

    原题地址:https://oj.leetcode.com/problems/copy-list-with-random-pointer/ 题意: A linked list is given such ...

  2. Android组件之自定义ContentProvider

    Android的数据存储有五种方式Shared Preferences.网络存储.文件存储.外储存储.SQLite,一般这些存储都只是在单独的一个应用程序之中达到一个数据的共享,有时候我们需要操作其他 ...

  3. typescript 的一种引入文件的方式 Triple-Slash Directives

    ---恢复内容开始--- /// reference 原文: https://www.typescriptlang.org/docs/handbook/triple-slash-directives. ...

  4. elasticSearch nested exist与missing查询

    elasticSearch nested查询,简单意义上,你可以理解为,它不会被索引,只是被暂时隐藏起来,而查询的时候,开关就是使用nested query/filter去查询 下面我有一个例子,是查 ...

  5. OAuth 2.0 RFC 框架 中文

    Internet Engineering Task Force (IETF) D. Hardt, Ed.Request for Comments: 6749 MicrosoftObsoletes: 5 ...

  6. [Javascript] Closure Cove, Common mistake

    They’ve got a problem with their existing code, which tries to use a closure. Check it out: function ...

  7. tcpdump-根据IP查看程序与服务都用了哪些端口

    tcpdump -i em1 -tttt src 116.3.248.157 and port ! 6869 -nn -i 指定端口 -tttt 附带时间戳 -nn 解析域名与端口信息 ####### ...

  8. U872-结算成本处理步骤及索引处理

    U872每月都须要做月结,对于制造企业来说,结算成本处理是不可缺少的一个处理环节,每次查询出来待暂估记录也比較多(我接触到的有3万左右),暂估时间一般要2-3小时左右,若调用的大表索引碎片多时,会须要 ...

  9. win7,8,10取得|取消管理员权限

    取得: Windows Registry Editor Version 5.00[HKEY_CLASSES_ROOT\*\shell\runas]@=”管理员取得所有权”“NoWorkingDirec ...

  10. Druid register mbean error

    key: [com.alibaba.druid.stat.DruidDataSourceStatManager.addDataSource(DruidDataSourceStatManager.jav ...