02--02 Interprocess Communication - Message Queuing, and Code Implementation

Keywords: Linux Operating System

1. What is a message queue

Message queuing provides a way to send a data block from one process to another.Each data block is considered to contain a type, and the receiving process can independently receive different types of data structures. We can avoid the synchronization and blocking of named pipes by sending messages. However, message queues, like named pipes, have a maximum length limit for each data block.

Linux uses macros MSGMAX and MSGMNB to limit the maximum length of a message and a queue.

2. Using Message Queuing on Linux

Linux provides a series of function interfaces for message queues that allow us to easily use for interprocess communication. It is used similarly to the other two System V PIC mechanisms, semaphores and shared memory.

1. msgget function

This function is used to create and access a message queue. Its prototype is:

	
int msgctl(int msgid, int command, struct msgid_ds *buf);

command is the action to be taken, which can take three values.

IPC_STAT: Set the data in the msgid_ds structure to the current associated value of the message queue, that is, overwrite the value of msgid_ds with the current associated value of the message queue.

IPC_SET: If the process has sufficient privileges, 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 queue mode and the structure of access rights. 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;
};

3. Use Message Queuing for Interprocess Communication

Here we will write two programs, msgreceive and msgsned, to represent receiving and sending information. Normally, we allow both programs to create messages, but only after the recipient has received the last message, does it delete it.

The source code for the program that receives the information is msgreceive.c:

/*Communicate using Message Queuing*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>
struct msg_st
{  
    long int msg_type; 
    char text[BUFSIZ];
};
int main()
{  
    int running = 1;   
    int msgid = -1;
    struct msg_st data;
    long int msgtype = 0; //Note 1//Create Message Queue   
    msgid = msgget((key_t)1234, 0666 | IPC_CREAT); 
    if(msgid == -1)
    {      
        fprintf(stderr, "msgget failed with error: %d\n", errno);  
        exit(EXIT_FAILURE);
    }   //Get messages from the queue until an end message is encountered 
    while(running) 
    {  
        if(msgrcv(msgid, (void*)&data, BUFSIZ, msgtype, 0) == -1)  
        {  
            fprintf(stderr, "msgrcv failed with errno: %d\n", errno);  
            exit(EXIT_FAILURE);    
        }  
        printf("You wrote: %s\n",data.text);        //end Encountered  
        if(strncmp(data.text, "end", 3) == 0)      
            running = 0;   
    }   //Delete message queue   
    if(msgctl(msgid, IPC_RMID, 0) == -1)   
    {      
        fprintf(stderr, "msgctl(IPC_RMID) failed\n");  
        exit(EXIT_FAILURE);
    }  
    exit(EXIT_SUCCESS);
}

The source code for the program that sent the message, msgsend.c, is:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/msg.h>
#include <errno.h>
#define MAX_TEXT 512
struct msg_st
{  
    long int msg_type; 
    char text[MAX_TEXT];
};
int main()
{  
    int running = 1;   
    struct msg_st data;
    char buffer[BUFSIZ];
    int msgid = -1;     //Create message queue
    msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
    if(msgid == -1)
    {  
        fprintf(stderr, "msgget failed with error: %d\n", errno);  
        exit(EXIT_FAILURE);
    }   //Write a message to the message queue until the end is written
    while(running) 
    {       //Input data 
        printf("Enter some text: ");   
        fgets(buffer, BUFSIZ, stdin);  
        data.msg_type = 1;    //Note 2    
        strcpy(data.text, buffer);      //Send data to queue  
        if(msgsnd(msgid, (void*)&data, MAX_TEXT, 0) == -1) 
        {      
            fprintf(stderr, "msgsnd failed\n");    
            exit(EXIT_FAILURE);    
        }       //Enter end to end input    
        if(strncmp(buffer, "end", 3) == 0)     
            running = 0;   
        sleep(1);
    }  
    exit(EXIT_SUCCESS);
}

4. Comparison of message queues and named pipes

Message queues have many similarities with named pipes. Like named pipes, processes that communicate with message queues can be unrelated processes, and they all transmit data by sending and receiving. In named pipes, data is sent in write, data is received in read, and data is sent in msgsnd, and data is received in message queuesReceive data using msgrcv. They also have a maximum length limit for each data.

The advantages of message queues over named pipes are that 1. Message queues can also exist independently of sending and receiving processes, eliminating the difficulties that may arise when synchronizing named pipes open and close. 2. Sending messages also avoids synchronization and blocking problems with named pipes, and does not require the process to provide its own synchronization methods.3, the receiver can selectively receive data through the message type, rather than by default, as in a named pipe.

Posted by shturm681 on Sat, 18 Sep 2021 21:32:51 -0700