This article describes the last SYSTEMV IPC, which is Message Queuing. Message Queuing provides a way to send messages from one process to another. and each block of data is considered to contain a type, so the receiving process can receive separate blocks of data that contain different types. In real-world usage, use scenarios to decide whether to use Message Queuing. The scenario I've encountered is that the process needs to be ordered to share a message with a type. In addition, I cannot provide a more appropriate usage scenario, perhaps most people prefer to use UNIX domain sockets or shared memory to replace this approach.
The following is a detailed description of shared memory.
First is the header file, similar to the other two IPC, the header file of the message queue is <sys/msg.h>, and may also need to include <sys/types.h> and <sys/ipc.h>
The functions are as follows:
int msgctl (int msg_id, int command, struct msg_ds *buf);
int Msgget (key_t key, int flag);
int MSGRCV (int msg_id, void *msg_ptr, size_t msg_sz, long int msgtype, int msgflag);
int msgsnd (int msg_id, void * msg_ptr, size_t msg_sz, int msgflag);
1. Msgget creates a unique token for the message queue for other functions to call. Of course, you can use Ipc_private at key to specify that only in-process use. Flag optional low nine-bit for Message Queuing permissions. Other marks are ipc_creat Creates or obtains a message queue that already exists. If the mating ipc_excl is only allowed to be created, then an error is returned if the message queue already exists.
Msgget successfully returns the ID of the message queue, returns 1 if failed
2. MSGCTL Message Queue control function, the first parameter is the ID returned by Msgget, the second parameter to the operation of the message queue, most of the time, we just remember Ipc_rmid on the line. How else do I use grapefruit? For example, you can pass the IPC_STAT,IPC_ Set Gets or sets the state of the message queue. The following buf are some of the properties of Message Queuing.
Msgctl successful call returns 0, failure returns-1
3. Msgrcv as the name implies, is to receive a message. The first parameter is the ID returned by Msgget, and the second argument is a message structure. After introducing this function, let's look at the structure. The third parameter, MSG_SZ, is the size of the second parameter. The fourth parameter, which specifies the type of data to receive. But this is not the only way to use it. Msg_type implements a simple priority and filtering. If it is greater than 0, then only the value specified by Msg_type is accepted, if it is equal to 0, are accepted in order. If less than 0, the message type is received that is less than or equal to the absolute value of Msg_type. The last parameter flag is used to control what action the process takes if there is no message. Optional markings have ipc_nowait, if this tag is developed, The process exits without a message, if the message is not specified. Then the process waits.
MSGRCV successfully returns the number of bytes in the receive buffer, failure returns-1
4. MSGSND sends a message. The first parameter msg_id, Msgget gets to the message queue token, the second parameter msg_ptr, the content to be sent. The third parameter, MSG_SZ, specifies the length of the message. The fourth parameter, Msgflag, specifies what will happen when the message queue is full or when the specified upper limit of the system is reached. If ipc_nowait is specified, it does not wait for direct return-1, which is blocked if this option is not specified.
The MSGSND successfully returned the number of bytes written to the buffer, and the failure returned-1.
The next thing to say about the message body structure, is actually a struct, the difference is that the first four bytes must be a long int type to develop the message type.
struct MSG
{
long int msg_type;
void *buf; The content here is free to play.
}
OK, let's design a scene below. Three processes are chatting with each other. Who gets the semaphore? The process that did not get the semaphore waits for the message to be accepted.
Let's summarize the problems you have encountered. I thought I would, but I still have a lot of details to pay attention to.
1. The third parameter of the MSGSND function is the length of the message body, excluding the type. sizeof (struct msg_struct) when I started. I'm sure it won't work. After seeing this constraint later, I subtracted a sizeof (int). Find it or not. Not all lengths, not int lengths, but long int. I can't blame myself for the program that I started with on 32-bit machines. I didn't notice it, and I didn't have a problem. But these two days changed the system, Replaced with a 64-bit system. That's why I met this problem. Very depressed.
2. scanf. Learning the C language, only to find that I will not use the scanf page. This thing is really too bad. I entered the content. But there is no output. It's mostly about the buffer zone. I did not go to the bottom of the line. Change the function directly and use the fgets.
3. Because it is almost the same code, in the release of resources above, the page has a problem, the first process to exit, delete the message queue, the second process to read the time will return an error. So that the second process cannot be freed.
In summary, the revised code is as follows:
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include < errno.h> #include <sys/types.h> #include <sys/sem.h> #include <sys/msg.h> #define Msg_len 1024# Define Msg_type 1union Semun {int val; /* Value for Setval */struct SEMID_DS *buf; /* Buffer for Ipc_stat, Ipc_set */unsigned short *array; /* Array for GETALL, SETALL */struct seminfo *__buf; /* Buffer for Ipc_info (linux-specific) */};struct msg_buffer{long int msg_type; Char Buffer[msg_len];}; int main (int argc, char * * argv) {int ret; int quit_talking = 0; int sem_id, msg_id; struct SEMBUF sem_p; struct SEMBUF sem_v; Union Semun option; struct Msg_buffer msg; msg_id = Msgget ((key_t) 123456, 0666 | Ipc_creat); if (msg_id < 0) {perror ("Create msg failed\n"); Exit (Exit_failure); } sem_id = Semget ((key_t) 123478, 1, 0666 | Ipc_creat); If (sem_id < 0) {perror ("sem create failed\n"); Exit (Exit_failure); } option.val = 1; Note 1 ret = semctl (sem_id, 0, setval, option); if (Ret < 0) {perror ("Semctl failed\n"); Exit (Exit_failure); } sem_p.sem_num = 0; Sem_p.sem_op =-1; SEM_P.SEM_FLG = Sem_undo; Sem_v.sem_num = 0; Sem_v.sem_op = 1; SEM_V.SEM_FLG = Sem_undo; while (quit_talking = = 0) {semop (sem_id, &sem_p, 1); Bzero (&msg, sizeof (struct msg_buffer)); ret = MSGRCV (msg_id, &msg, sizeof (struct msg_buffer)-sizeof (long int), 1, ipc_nowait); if (Ret > 0) {printf ("Msgtype is%ld, MSG is%s\n", Msg.msg_type, Msg.buffer); if (strncmp (Msg.buffer, "End", 3) = = 0) {quit_talking = 1; Continue } bzero (&msg, sizeof (struct msg_buffer)); } printf ("Please input your msg\n"); Fgets (Msg.buffer, Msg_leN, stdin); Msg.msg_type = Msg_type; Msgsnd (msg_id, &msg, strlen (Msg.buffer), ipc_nowait); if (strncmp (Msg.buffer, "End", 3) = = 0) {quit_talking = 1; } semop (sem_id, &sem_v, 1); } ret = Semctl (sem_id, 0, ipc_rmid, option); if (Ret < 0) {printf ("sem rm failed\n"); Exit (Exit_failure); } sleep (1); ret = Msgctl (msg_id, Ipc_rmid, NULL); if (Ret < 0) {printf ("msg rm failed\n"); Exit (Exit_failure); } return 0;}
Note 1: The first copy, the Val is set to 1, the other copies here are 0. See my other blog, IPC (SYSTEMV) Semaphore.
I was going to write a slightly more complicated example. But thought for a long, not very good writing, and also not conducive to understanding. So I wrote a relatively simple one. The results are as follows:
IPC (SYSTEMV) Message Queuing