System V消息队列

1. 概述

System V消息队列使用消息队列标识符标识,和Posix消息队列一样,发送消息和接收消息的线程(进程)是相互独立、互不依赖的。
对于系统中的每个消息队列,内核维护一个定义在sys/msg.h头文件中的结构,其中带注释的是我们需要关注的成员变量。

struct msqid_ds
{
    struct ipc_perm msg_perm;
    struct msg     *msg_first; //指向队列中第一条消息
    struct msg     *msg_last;  //指向队列中最后一条消息
    msglen_t       msg_cbytes; //消息队列当前第几个字节
    msgqnum_t      msg_qnum;   //消息队列当前第几条消息
    msglen_t       msg_qbytes; //消息队列允许的最大字节数,仅针对消息数据,不包括与每个消息关联的长整型消息类型
    pid_t          msg_lspid;
    pid_t          msg_lrpid;
    time_t         msg_stime;a
    time_t         msg_rtime;
    time_t         msg_ctime;
};

2. 消息队列API

msgget

msgget用于创建一个新的消息队列或访问一个已存在的消息队列,参数key和oflag的含义及使用方法和semget一样,不再赘述。

//成功返回消息队列标识符,失败返回-1
int msgget(key_t key, int oflag);

msgsnd

msgsnd用于向消息队列中添加一条消息。

//成功返回0,失败返回-1
int msgsnd(int msqid, const void *ptr, size_t length, int flag);

参数说明:

  • msqid是msgget返回的标识符
  • ptr是一个由应用程序按如下模板定义的struct sembuf结构指针,只要保证第一个成员变量是long type即可,其后的数据部分可根据需要任意扩展
struct msgbuf
{
    long mtype;       /* message type, must be > 0 */
    char mtext[1];    /* message data */
};
  • length是待发送消息的长度,即消息类型之后的用户自定义数据的长度,该长度可以是0
  • flag可以是0或者IPC_NOWAIT,一般设为0

msgrcv

msgrcv用于从消息队列中取出一条消息。

//成功返回实际读入缓冲区的数据长度,失败返回-1
int msgrcv(int msqid, void *ptr, size_t length, long type, int flag);

参数说明:

  • msqid是msgget返回的标识符
  • ptr指向数据接收缓冲区,它应该和msgsnd的ptr具有同样的struct sembuf结构
  • length为缓冲区大小
  • type用于指定希望从消息队列中读出什么样的消息
  • flag可以是0、IPC_NOWAIT或MSG_NOERROR,一般设为0

msgrcv第四个参数type用于指定希望从消息队列中读出什么样的消息,假设有消息队列中有三条消息:

  • 第一条消息的类型为100,长度为1
  • 第二条消息的类型为200,长度为2
  • 第二条消息的类型为300,长度为3

那么:

  • type = 0:返回队列中第一个消息
  • type > 0:返回消息类型等于type的第一个消息
  • type < 0:返回消息类型 <= abs(type)的消息中类型值最小的第一个消息

msgctl

msgctl提供在一个消息队列上的各种控制操作。

//成功返回0,失败返回-1
int msgctl(int msqid, int cmd, struct msqid_ds *buf);

msgctl支持三个cmd命令:

  • IPC_RMID:从系统中删除由msqid指定的消息队列,此时第三个参数被忽略,设为NULL即可
  • IPC_STAT:通过buf参数返回由msqid指定消息队列对应的msqid_ds结构
  • IPC_SET:通过buf参数返回由msqid指定消息队列对应的msqid_ds结构,但仅设置以下4个成员:msg_perm.uid、msg_perm.gid、msg_perm.mode和msg_perm.qbytes

3. 简单的程序

代码实现

common.h

#ifndef _COMMON_H_
#define _COMMON_H_

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

#define FTOK_FILE          "/home/delphi/ftok.file"
#define FTOK_ID            1

#define MSG_RD_PERMISSION  0444
#define MSG_WR_PERMISSION  0222
#define MSG_RW_PERMISSION  (MSG_RD_PERMISSION | MSG_WR_PERMISSION)

#define MAX_MSG_LEN        (8192 + sizeof(long))

struct msgbuf
{
    long type;
    char *data;
};

#endif

msgcreate.c

#include "common.h"

int main()
{
    key_t key = ftok(FTOK_FILE, FTOK_ID);
    int oflag = IPC_CREAT | MSG_RW_PERMISSION;
    int msgid = msgget(key, oflag);

    if (msgid >= 0)
    {
        printf("msgget create success, msgid = %d\n", msgid);
    }

    return 0;
}

msgsnd.c

#include "common.h"

int main(int argc, char **argv)
{
    int msgid;
    int msglen;
    long msgtype;
    struct msgbuf *msg;

    msgid   = msgget(ftok(FTOK_FILE, FTOK_ID), MSG_WR_PERMISSION);
    msglen  = atoi(argv[1]);
    msgtype = atol(argv[2]);

    msg = (struct msgbuf *)calloc(sizeof(long) + msglen, sizeof(char));
    msg->type = msgtype;

    msgsnd(msgid, msg, msglen, 0);

    return 0;
}

msgrcv.c

#include "common.h"

int main(int argc, char **argv)
{
    int msgid;
    int rcvlen;
    long msgtype;
    struct msgbuf *msg;

    msgid   = msgget(ftok(FTOK_FILE, FTOK_ID), MSG_RD_PERMISSION);
    msgtype = atol(argv[1]);
    msg = (struct msgbuf *)calloc(MAX_MSG_LEN, 1);

    rcvlen = msgrcv(msgid, msg, MAX_MSG_LEN, msgtype, 0);
    printf("read %d bytes, type = %ld\n", rcvlen, msg->type);

    return 0;
}

msgrmid.c

#include "common.h"

int main(int argc, char **argv)
{
    int msgid = msgget(ftok(FTOK_FILE, FTOK_ID), 0);
    msgctl(msgid, IPC_RMID, 0);

    return 0;
}

代码测试

posted @ 2019-09-18 22:25  原野追逐  阅读(1146)  评论(0编辑  收藏  举报