In this chapter we shall learn about:
1. Introduction
2. How to connect to a message queue?
3. How to send a message queue?
4. How you initialize a “msgsnd()”.
5. How to receive a message queue?
6. Destroying a message queue.
7. Example to send a message
8. Example to receive a message
Introduction:
1. In this chapter we shall learn about system V message queue.
2. Two or more process can communicate with each other using message queue.
3. Message Queues are like linked list, messages can be sent in a queue and retrieved in a queue.
4. Each message queue is identified by unique IPC identifier.
5. The process that uses message queue should share common key in order to access the queue.
6. Each message has a message type associated with it.
7. Message Queues are based on a system buffer resource, hence if there is a pileup of message queue, then system will hang.
8. The max size of message queue is 4056. In linux it is defined under linux/msg.h as:
#define MSGMAX 4056
Now let us understand Message queue by parts:
1. How to connect to a message queue?
“msgget()” function is used get a message queue or create if it did not exist.
Function Prototype:
int msgget(key_t key, int msgflg)
Here,
key : It is a unique identifier, if any process wants to connect to the queue, it should have to use the same key.
As key is a “long” data type, you can use any integer to set the key.
Or you can also use “ftok()” known as “file to key”. The function accepts 2 arguments, first is file path and the next is a id. “ftok()” will use these 2 arguments and then will create a unique key. The other program trying to access this queue should use the same parameters.
Function prototype for ftok is:
key_t ftok(const char *path, int id);
msgflg : It is an octal number, with the for the queue’s permissions and control flags.
So finally we can call msgget as below:
#include <sys/msg.h> key = ftok("/home/beej/somefile", 'b'); msqid = msgget(key, 0666 | IPC_CREAT);
2. How to send a message queue?
Once the call to “msgget()” is successful, we can now send or receive messages.
To send a message we use “msgsnd()” function. It’s prototype is:
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
Here:
msqid : It is the message queue identifier returned by msgget()
msgp : It is the pointer of the message that you want to put it in queue.
msgsz : It is the size in bytes of the data to add to the queue.
msgflg : It allows you to set optional flag parameters.
To send a message, there should be a message buffer. The C library has provided a default template structure “msgbuf” that is present in “sys/msg.h” as:
struct msgbuf { long mtype; char mtext[1]; };
From the above, you can see that, the first member is long data type, which is used to hold the type of message.
The second member is a char with 1 byte size to hold the data.
But how can we send only 1 byte of data? It appears that, you can create your own message buffer. But the first element should be a long.
Below I have created my own message buffer.
struct my_msgbuf { long mtype; /* must be positive */ struct info { char name[50]; int id; } info; };
Below is how you initialize a “msgsnd()”.
#include <sys/msg.h> #include <stddef.h> key_t key; int msqid; struct my_msgbuf mb = {2, { "www.prodevelopertutorial.com", 345 } }; key = ftok("/home/aj/myFile", 'b'); msqid = msgget(key, 0666 | IPC_CREAT); //send the message msgsnd(msqid, &mb, sizeof(struct my_msgbuf), 0);
3. How to receive a message queue?
To receive a message we use “msgrcv()” function. It’s prototype is:
int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
Here all the parameters is same as for msgget(). Except for “msgtyp”. “msgtyp” should be same as the type in msgbuf when you are sending a message. In our case it is “2”.
Below is how you receive a message:
#include <sys/msg.h> #include <stddef.h> key_t key; int msqid; struct my_msgbuf mb; // to accept a message key = ftok("/home/aj/myFile", 'b'); msqid = msgget(key, 0666 | IPC_CREAT); //to receive a message msgrcv(msqid, &mb, sizeof(struct my_msgbuf), 2, 0);
4. Destroying a message queue.
It is important to destroy the message queue that you have created. Because, until you destroy the message, that message queue will be in the memory.
So it is important to destroy the message queue that you have created after the work is completed.
To delete a message queue we use “msgctl()” function. It’s prototype is:
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
And we use it as below;
msgctl(msqid, IPC_RMID, NULL);
Full working example of message queue:
Example to send a message:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #define MAXSIZE 128 typedef struct msgbuf { long mtype; char mtext[MAXSIZE]; }msgbuf; int main() { int msqid; int msgflg = IPC_CREAT | 0666; key_t key; struct msgbuf sbuf; size_t buflen; key = 1234; if ((msqid = msgget(key, msgflg )) < 0) { perror("msgsnd"); exit(1); } //Message Type sbuf.mtype = 1; printf("Enter a message:"); scanf("%[^\n]",sbuf.mtext); getchar(); buflen = strlen(sbuf.mtext) + 1 ; if (msgsnd(msqid, &sbuf, buflen, IPC_NOWAIT) < 0) { printf ("Error while seding a message"); perror("msgsnd"); exit(1); } else printf("Message Sent\n"); exit(0); }
Example to receive a message:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdio.h> #include <stdlib.h> #define MAXSIZE 128 typedef struct msgbuf { long mtype; char mtext[MAXSIZE]; } msgbuf; int main() { int msqid; key_t key; struct msgbuf rcvbuffer; key = 1234; if ((msqid = msgget(key, 0666)) < 0) { perror("msgsnd"); exit(1); } //Receive an answer of message type 1. if (msgrcv(msqid, &rcvbuffer, MAXSIZE, 1, 0) < 0) { perror("msgrcv"); exit(1); } printf("%s\n", rcvbuffer.mtext); exit(0); }