专栏首页开发与安全linux网络编程之System V 消息队列(一):消息队列内核结构和msgget、msgctl 函数

linux网络编程之System V 消息队列(一):消息队列内核结构和msgget、msgctl 函数

一、消息队列

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 产生的是私有的消息队列。

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

/*************************************************************************
    > 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,如下:

/*************************************************************************
    > 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

/*************************************************************************
    > 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》

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • linux网络编程之System V 消息队列(二):消息队列实现回射客户/服务器和 msgsnd、msgrcv 函数

    一、msgsnd 和 msgrcv 函数   #include <sys/types.h>   #include <sys/ipc.h>   #inclu...

    s1mba
  • HTTP 协议详解 (增删减及标注)

    注:来源http://blog.csdn.net/gueter/article/details/1524447 略有增删减及标注

    s1mba
  • linux系统编程之文件与I/O(五):文件的内核结构file和dup实现重定向

    一、打开文件内核数据结构 1、一个进程打开两个文件 ? 文件状态标志:读、写、追加、同步、非阻塞等 2、一个进程两次打开同一文件 ? 3、两个进程打开同一文...

    s1mba
  • 在CentOS 6.5上构建Apache Thrift

    从最小的安装开始,需要以下步骤来在Centos 6.5上构建Apache Thrift。 本示例使用当前的开发主分支从源代码构建。 这些说明也应适用于从0.9....

    ccf19881030
  • 读者问:学完SSM,该学什么呢?

    在之前,我写过一篇《如何入门Java的文章》,无论是看公众号还是各大的博客的同学大多数都是比较认可我所讲的路线的。

    Java3y
  • 【干货】双模IT驱动下的持续交付管理平台设计

    陈能技,现任职隆正互联,担任研发集群部总监,主要负责超级软件工厂IT基础设施建立、DevOps体系推行、公司产品和解决方案售前。曾任职新炬网络,担任首席架构师,...

    杨振涛
  • PHP开启opcache提升代码性能

    luxixing
  • 已经30+了,前端开发的中年危机如何渡过?

    真心的说,不是我爱写这些,而是总有人问我这方面的问题。第一句跟我说,“我今年27了,想要学前端开发能行吗”?我说什么啊,你才27很年轻啊,学呗。第二句话就问我,...

    web前端教室
  • 一款比谷歌更有趣的 AI 搜索引擎 Magi,或许这才是次时代搜索引擎该有的样子!

    在信息爆炸的今天,互联网上充斥着各种各样的信息,我们日常不可避免的需要依赖搜索引擎来快速找到有用的信息。由于每家的搜索引擎算法和规则不一样,这必然会导致我们在使...

    iMike
  • 结构型模式:组合模式

    姓名 :组合模式 英文名 :Composite Pattern 价值观 :专门解决各种树形疑难杂症 个人介绍 : Compose objects into tr...

    LieBrother

扫码关注云+社区

领取腾讯云代金券