System V message queue

Posted by cytech on Wed, 18 Sep 2019 16:41:56 +0200

Catalog

1. overview

System V message queues are identified by message queue identifiers. Like Posix message queues, the threads (processes) that send and receive messages are independent and independent of each other.
For each message queue in the system, the kernel maintains a structure defined in the sys/msg.h header file, where annotated members are variables that we need to focus on.

struct msqid_ds
{
    struct ipc_perm msg_perm;
    struct msg     *msg_first; //Point to the first message in the queue
    struct msg     *msg_last;  //Point to the last message in the queue
    msglen_t       msg_cbytes; //The current number of bytes in the message queue
    msgqnum_t      msg_qnum;   //What message is the current message in the message queue
    msglen_t       msg_qbytes; //Maximum number of bytes allowed for message queues, for message data only, excluding long integer message types associated with each message
    pid_t          msg_lspid;
    pid_t          msg_lrpid;
    time_t         msg_stime;a
    time_t         msg_rtime;
    time_t         msg_ctime;
};

2. Message queue API

msgget

msgget is used to create a new message queue or access an existing message queue. The meaning and usage of the parameters key and oflag are the same as semget.

//Successful return of message queue identifier, failed return - 1
int msgget(key_t key, int oflag);

msgsnd

msgsnd is used to add a message to the message queue.

//Successful return 0, failed return - 1
int msgsnd(int msqid, const void *ptr, size_t length, int flag);

Description of parameters:

  • msqid is the identifier returned by msgget
  • ptr is a struct sembuf structure pointer defined by the application according to the following template, as long as the first member variable is guaranteed to be long type, then the data part can be expanded as needed.
struct msgbuf
{
    long mtype;       /* message type, must be > 0 */
    char mtext[1];    /* message data */
};
  • Length is the length of the message to be sent, that is, the length of user-defined data after the message type, which can be 0
  • flag can be 0 or IPC_NOWAIT, usually set to 0

msgrcv

msgrcv is used to extract a message from the message queue.

//Successfully returns the length of the data actually read into the buffer, and fails to return - 1
int msgrcv(int msqid, void *ptr, size_t length, long type, int flag);

Description of parameters:

  • msqid is the identifier returned by msgget
  • ptr points to the data receiving buffer, which should have the same struct sembuf structure as the ptr of msgsnd
  • length is the buffer size
  • type is used to specify what messages you want to read from the message queue
  • flag can be 0, IPC_NOWAIT or MSG_NOERROR, generally set to 0

The fourth parameter type of msgrcv is used to specify what messages you want to read from the message queue, assuming that there are three messages in the message queue:

  • The first message has a type of 100 and a length of 1.
  • The second message has a type of 200 and a length of 2.
  • The second message has a type of 300 and a length of 3.

Then:

  • type = 0: Returns the first message in the queue
  • Type > 0: The first message that returns a message type equal to type
  • Type < 0: The first message that returns the message type <= ABS (type) with the smallest type value

msgctl

msgctl provides various control operations on a message queue.

//Successful return 0, failed return - 1
int msgctl(int msqid, int cmd, struct msqid_ds *buf);

msgctl supports three cmd commands:

  • IPC_RMID: Delete the message queue specified by msqid from the system, at which point the third parameter is ignored and set to NULL.
  • IPC_STAT: Returns the msqid_ds structure corresponding to the message queue specified by msqid through the buf parameter
  • IPC_SET: The buf parameter returns the msqid_ds structure corresponding to the message queue specified by msqid, but only four members are set: msg_perm.uid, msg_perm.gid, msg_perm.mode and msg_perm.qbytes.

3. Simple procedures

code implementation

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

Code testing

Topics: Linux Delphi