徐高翔的个人网站

进程间通信之消息队列

2013-07-24

软硬件环境

  • ubuntu 16.04 64bit

简介

消息队列是系统内核提供的一个用来保存消息的队列,是进程间通信的一种常用方法

相关数据结构

1、msgbuf

1
2
3
4
5
struct msgbuf
{
    long mtype;    /消息类型/
    char mtext[1]; /消息内容/
}

mtext不受其描述的限制,实际上mtext不仅可以保存字符,而且能保存任何形式的数据。因此程序员可以重新定义结构

1
2
3
4
5
struct mymsgbuf{
    long mtype;         /* 消息类型 */
    long request_id;    /* 请求标识符 */
    struct client info; /* 客户消息结构 */
};

需要注意的一点是,linux系统对消息类型的最大升序有所限制,在/usr/include/linux/msg.h中。

1
define MSGMAX 8192

2、msqid_ds

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct msqid_ds 
{
    struct ipc_perm msg_perm;     /消息队列的存取权限及其它一些信息,参见ipc_perm/
    struct msg msg_first;        / first message on queue,unused */
    struct msg msg_last;         / last message in queue,unused */
    __kernel_time_t msg_stime;    /* last msgsnd time */
    __kernel_time_t msg_rtime;    /* last msgrcv time */
    __kernel_time_t msg_ctime;    /* last change time */
    unsigned long msg_lcbytes;    /* Reuse junk fields for 32 bit */
    unsigned long msg_lqbytes;    /* ditto */
    unsigned short msg_cbytes;    /* current number of bytes on queue */
    unsigned short msg_qnum;      /* number of messages in queue */
    unsigned short msg_qbytes;    /* max number of bytes on queue */
    __kernel_ipc_pid_t msg_lspid; /* 最近一次向队列发送消息的进程的pid */
    __kernel_ipc_pid_t msg_lrpid; /* 最近一次从队列中取出的消息的进程的pid */
};

3、msg

1
2
3
4
5
6
7
8
struct msg
{
    struct msg msg_next;  /消息链表中的再一节点指针*/
    long msg_type;         /和结构msgbuf中的mtype一样/
    char msg_spot;        /消息内容,和msgbuf中的mtext一样*/
    time_t msg_stime;      /msgsnd time/
    short msg_ts;          /消息长度/
};

4、ipc_perm

1
2
3
4
5
6
7
8
9
10
struct ipc_perm
{
    __kernel_key_t    key;
    __kernel_uid_t    uid;
    __kernel_gid_t    gid;
    __kernel_uid_t    cuid;
    __kernel_gid_t    cgid;
    __kernel_mode_t    mode; 
    unsigned short    seq;
};

这个结构用来保存每个IPC对象的权限信息

相关函数

1、ftok()

1
2
3
4
#include <sys/types.h>
#include <sys/ipc.h>

key_t ftok(const char *pathname, int proj_id);

ftok()通过混合pathname所指文件的inode和minor device的值以及proj_id的值来产生关键字,示例

1
2
key_t key;
key = ftok(".","a"); //程序在同一目录下运行

2、msgget()

1
2
3
4
5
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg);

msgget()用来创建新的消息队列或者获取已有的消息队列。其中key是消息队列的关键字,用它来和已有的消息队列对象的关键字进行比较来判断消息队列是否已经创建,msgflg可取如下值

  • IPC_CREAT: 如果消息队列不存在,则创建,否则打开

  • IPC_EXCL : 与IPC_CREAT一起使用,IPC_CREAT | IPC_EXCL,如果消息队列不存在,则创建,否则返回错误

    除此以外,在msgflg中还可以和存取权限结合使用

    msgget()返回新建的消息队列对象的标识符,如果队列已经存在,返回-1

3、msgsnd()

1
2
3
4
5
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

msgsnd()用来向消息队列发送消息。msgid是消息队列对象的标识符(由msgget()得到),msgp指向消息所在的内存,msgsz是消息长度,msgsz = sizeof(struct mymsgbuf) - sizeof(long);
msgflg可取如下值

  • IPC_NOWAIT: 如果队列已满,消息不再写入队列,控制权返回调用函数的进程。如果不指定,进程将被阻塞直到消息可以被写入
  • 0 : 忽略标志位

4、msgrcv()

1
2
3
4
5
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);

msgrcv()用来从消息队列中取出消息。msgtype指定从消息队列中所取的消息的类型,如果msgtype为0,则不做类型检查直接返回队列中最旧的消息。
msgflg可以取如下值

  • IPC_NOWAIT: 如果消息队列为空,返回ENOMSG,控制权交给调用函数的进程,如果不指定这个参数,进程将被阻塞直到可以从队列中取出符合条件的消息为止。如果一个client正在等待的队列被删除,返回EIDRM。如果进程在阻塞等待过程中收到系统的中断信号,则返回EINTR
  • MSG_NOERROR: 如果函数取得的消息长度大于msgsz,将只返回msgsz长度的信息,剩余部分被丢弃。如果不指定这个参数,返回E2BIG,消息不被取出
  • 0 : 忽略标志位

5、msgctl()

1
2
3
4
5
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

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

msgctl()用来控制消息队列的行为。参数cmd是可对消息队列进行的操作

  • IPC_STAT: 取出消息队列的msqid_ds数据,并存入buf中
  • IPC_SET : 设置消息队列的msqid_ds结构中的msg_perm成员,设定的值由buf指向的msqid_ds结构给出
  • IPC_EMID: 将队列从内核中删除

本文链接 https://xugaoxiang.com/2013/07/24/进程间通信之消息队列/

推荐文章(由hexo文章推荐插件驱动)

使用支付宝打赏
使用微信打赏

请博主喝咖啡!