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;
}

代碼測試


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM