linuxc message queuing

-- see section 15.7 of advanced programming in unix environment for details

At the end of section 15.7 of advanced programming in UNIX environment, the advantages and disadvantages of message queuing are summarized. The conclusion is that they should no longer be used in new applications. Indeed, in pursuit of efficiency, we can use shared memory, and in pursuit of convenience, we can use pipes or UNIX domains. Message queuing is in such an awkward position.

correlation function

#include <sys/msg.h>
/*    Used to create and access a message queue
    key:  Like other IPC mechanisms, a program must provide a key to name a particular message queue
    msg:  flg Is a permission flag indicating the access permission of the message queue, which is the same as the access permission of the file
    Return value: returns the identifier (non-zero integer) of a message queue named after key, and returns - 1 in case of failure.
*/
int msgget(key_t  key, int msgflg);
/*    Used to add messages to the message queue
    msgid: Is the message queue identifier returned by the msgget function.
    msg_ptr: msg_ptr Is a pointer to the message to be sent
    msg_sz: It is the length of the message pointed to by msg_ptr. Note that it is the length of the message, not the length of the whole structure. That is to say, msg_sz is the length of the member variable excluding the long integer message type.
    msgflg: Used to control what happens when the current message queue is full or when a queued message reaches a system wide limit
    Return value: success, a copy of the message data will be put into the message queue, and 0 will be returned, and - 1 will be returned in case of failure.
*/
int msgsnd(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg); 
/*Used to get messages from a message queue
    msgid: Is the message queue identifier returned by the msgget function.
    msg_ptr: msg_ptr Is a pointer to the message to be sent
    msg_st:  Ditto
    msgtype: A simple receive priority can be implemented. If msgtype is 0, the first message in the queue is obtained. If its value is greater than zero, the first information with the same message type is obtained. If it is less than zero, the first message of type equal to or less than the absolute value of msgtype is obtained.
    msgflg: Used to control what happens when there is no message of the corresponding type in the queue to receive
    Return value: upon success, the function returns the number of bytes put into the receive buffer, the message is copied to the user allocated buffer pointed by msg_ptr, and then the corresponding message in the message queue is deleted. Return - 1 on failure.
*/
int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);
/*    Used to control message queues, similar to the shmctl function of shared memory
    msgid: Is the message queue identifier returned by the msgget function.
    Command: Is the action to be taken. It can take three values.
        IPC_STAT: Set the data in msgid UDS structure to the current association value of message queue, that is, overwrite the value of msgid UDS with the current association value of message queue.
        IPC_SET: If the process has sufficient permissions, set the current associated value of the message queue to the value given in the msgid? DS structure
        IPC_RMID: Delete message queue
    buf: Is a pointer to the msgid? DS structure, which points to the message queuing mode and access rights structure. The msgid? DS structure includes at least the following members:
        struct msgid_ds {  
            uid_t shm_perm.uid;  
            uid_t shm_perm.gid;  
            mode_t shm_perm.mode;  
        };
    Return value: 0 for success and - 1 for failure.
*/
int msgctl(int msgid, int command, struct msgid_ds *buf);

Example

Communication between client and server

//comm.h
#ifndef _COMM_H_
#define _COMM_H_

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

struct msgbuf
{
    long mtype;
    char mtext[1024];
};

#define SERVER_TYPE 1
#define CLIENT_TYPE 2

int createMsgQueue();
int getMsgQueue();
int destoryMsgQueue(int msg_id);
int sendMsgQueue(int msg_id, int who, char* msg);
int recvMsgQueue(int msg_id, int recvType, char out[]);

#endif
//comm.c
#include "comm.h"

static int commMsgQueue(int flags)
{
    key_t key = ftok("/tmp", 0x6666);
    if(key < 0)
    {
        perror("ftok");
        return -1;
    }

    int msg_id = msgget(key, flags);
    if(msg_id < 0)
    {
        perror("msgget");
    }
    return msg_id;
}

int createMsgQueue()
{
    return commMsgQueue(IPC_CREAT|IPC_EXCL|0666);
}

int getMsgQueue()
{
    return commMsgQueue(IPC_CREAT);
}

int destoryMsgQueue(int msg_id)
{
    if(msgctl(msg_id, IPC_RMID, NULL) < 0)
    {
        perror("msgctl");
        return -1;
    }
    return 0;
}

int sendMsgQueue(int msg_id, int who, char* msg)
{
    struct msgbuf buf;
    buf.mtype = who;
    strcpy(buf.mtext, msg);

    if(msgsnd(msg_id, (void*)&buf, sizeof(buf.mtext), 0) < 0)
    {
        perror("msgsnd");
        return -1;
    }
    return 0;
}

int recvMsgQueue(int msg_id, int recvType, char out[])
{
    struct msgbuf buf;
    int size=sizeof(buf.mtext);
    if(msgrcv(msg_id, (void*)&buf, size, recvType, 0) < 0)
    {
        perror("msgrcv");
        return -1;
    }

    strncpy(out, buf.mtext, size);
    out[size] = 0;
    return 0;
}
//server.c
#include "comm.h"

int main()
{
    int msgid = createMsgQueue();

    char buf[1024] = {0};
    while(1)
    {
        recvMsgQueue(msgid, CLIENT_TYPE, buf);
        if(strcasecmp("quit", buf) == 0)
            break;
        printf("client# %s\n", buf);

        printf("Please enter# ");
        fflush(stdout);
        ssize_t s = read(0, buf, sizeof(buf));
        if(s>0)
        {
            buf[s-1]=0;
            sendMsgQueue(msgid, SERVER_TYPE, buf);
            printf("send done, wait recv...\n");
        }
    }

    destoryMsgQueue(msgid);
    return 0;
}
//client.c
#include "comm.h"

int main()
{
    int msgid = getMsgQueue();

    char buf[1024] = {0};
    while(1)
    {
        printf("Please Enter# ");
        fflush(stdout);
        ssize_t s = read(0, buf, sizeof(buf));
        if(s > 0)
        {
            buf[s-1]=0;
            sendMsgQueue(msgid, CLIENT_TYPE, buf);
            if(strcasecmp("quit", buf) == 0)
                break;
            printf("send done, wait recv...\n");
        }

        recvMsgQueue(msgid, SERVER_TYPE, buf);
        printf("server# %s\n", buf);
    }
    return 0;
}

Operation result

root@jonathan-pc:~/test/msg# ls
client.c  comm.c  comm.h  server.c
root@jonathan-pc:~/test/msg# gcc client.c comm.c -o c
root@jonathan-pc:~/test/msg# gcc server.c comm.c -o s
root@jonathan-pc:~/test/msg# ./s
client# hello
Please enter# nihao
send done, wait recv...
root@jonathan-pc:~/test/msg#
root@jonathan-pc:~/test/msg# ./c
Please Enter# hello
send done, wait recv...
nihaoserver# nihao
Please Enter# quit
send done, wait recv...

Keywords: C Unix Programming less

Added by Ekano on Tue, 22 Oct 2019 18:32:22 +0300