一、消息队列

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. Android中XML解析-SAX解析

    昨天由于时间比较匆忙只写了Android中的XML解析的Dom方式,这种方式比较方便,很容易理解,最大的不足就是内容多的时候,会消耗内存.SAX(Simple API for XML)是一个解析速度快 ...

  2. scala 学习笔记八 简洁性

    Scala可以简洁地表示概念,有时甚至可以说过于简洁. 1.消除中间结果 在组合表达式中,最后一个表达式会变成整个表达式的结果.下面的例子中,值会被捕获到val result中,然后result从方法 ...

  3. SQL-重复记录查询的几种方法

    1.查找表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断 select * from people where peopleId in (select peopleId from ...

  4. 【转】gcc选项

    http://zodiac1111.github.io/blog/config-gcc-warning/

  5. Bootstrap全局CSS样式之表格

    .table--基础表格样式. .table-striped--给<tbody>之内的每一行添加斑马条纹样式: .table-bordered--为表格添加边框: .table-hover ...

  6. 如何使用奥特歌词制作双语LRC字幕

    AutoLyric(奥特歌词)使用常见问题和技巧 1.如何设置桌面歌词字体的大小? 桌面歌词字体的大小由桌面歌词窗口的缩放来条设置,把鼠标放在桌面歌词上稍后就会出现半透明的窗口,对该窗口就可以进行拖动 ...

  7. ZH奶酪:【阅读笔记】Deep Learning, NLP, and Representations

    中文译文:深度学习.自然语言处理和表征方法 http://blog.jobbole.com/77709/ 英文原文:Deep Learning, NLP, and Representations ht ...

  8. MySQL Cluster管理节点配置文件-数据节点4G内存

    自己测试机器上搭建使用,大家可以参考一下 [NDBD DEFAULT] #TotalSendBufferMemory = 256M NoOfReplicas=2 DataMemory=2500M In ...

  9. Oracle体系结构一(学习笔记)

    总体结构分为三个部分:SGA,PGA,FILE文件 按功能分: 存储结构  存储结构对应关系  主要文件: 数据文件: 每个数据文件只与一个数据库相关联 一个表空间可以包含一个或者多个数据文件 一个数 ...

  10. jersey获取各个参数的总结

    service端: @Path("/hello") public class HelloService { @GET @Produces("text/plain" ...