1. msgsnd and msgrcv Functions
# Include <sys/types. h>
# Include <sys/IPC. h>
# Include <sys/msg. h>
Function: adds a message to the message queue.
Prototype int msgsnd (INT msqid, const void * msgp, size_t msgsz, int msgflg );
Parameters
Msgid: ID of the Message Queue returned by the msgget Function
Msgp: A pointer pointing to the message structure to be sent
Msgsz: refers to the message length pointed to by msgp. This length does not include the long int that saves the message type.
Msgflg: controls what will happen when the current message queue is full or when it reaches the system
Return Value: 0 is returned for success;-1 is returned for failure.
Msgflg = ipc_nowait indicates that the queue is full and does not wait, and an eagain error is returned. 0 indicates blocking wait
The message structure is restricted in two aspects. First, the specific data must be smaller than the upper limit msgmax. Second, it must start with a long int, and the receiver function will use this long integer to determine the message type.
The message structure Reference is as follows:
Struct msgbuf {
Long mtype;
Char mtext [1];
};
The mtext field is an array (or other structure) whose size is specified by msgsz, a nonnegative integer value. Messages of zero length (I. e., no mtext field) are permitted.
That is, the mtex area can be an array or struct, And the size is specified by the msgsz parameter.
Function: receives messages from a message queue.
Prototype ssize_t msgrcv (INT msqid, void * msgp, size_t msgsz, long msgtyp, int msgflg );
Parameters
Msgid: ID of the Message Queue returned by the msgget Function
Msgp: A pointer pointing to the message structure to be received
Msgsz: refers to the message length pointed to by msgp. This length does not include the long int that saves the message type.
Msgtype: a simple form of receiving priority.
Msgflg: controls what will happen when there are no corresponding types of messages in the queue for receiving.
Returned value: the number of characters actually placed in the receiving buffer is returned successfully. If the return value fails,-1 is returned.
Msgtype = 0: the first message in the queue is returned.
Msgtype> 0 return the message with the first type equal to msgtype in the queue
Msgtype <0 returns the message whose first type is smaller than or equal to the absolute value of msgtype in the queue, and is the minimum message type that meets the condition.
Msgflg = ipc_nowait. If the queue does not have readable messages and does not wait, the enomsg error is returned.
Msgflg = msg_noerror. The message is truncated when the message size exceeds msgsz.
Msgtype> 0 and msgflg = msg_0000t. The receiving type is not equal to the first message of msgtype.
Ii. Message Queue implementation
In the previous series of articles, we used socket sockets to implement the echo client/server program. Now we try to use message queue to implement it, mainly by using the two functions msgsnd and msgrcv described above.
For the server side, if the type of a message structure received is 1, it indicates a customer request, and the first four bytes of the mtex field store the PID of different processes, the subsequent bytes are the real data. When the server returns the client, the PID is used as the type, and the mtex is the actual data. The client only receives the corresponding type of data, so different clients can be distinguished.
The procedure is as follows:
Echoser. c
C ++ code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
|
# Include <stdlib. h> # Include <sys/IPC. h> # Include <sys/msg. h> # Include <sys/types. h> # Include <unistd. h> # Include <errno. h> # Include <string. h># Define err_exit (m )\ Do {\ Perror (m );\ Exit (exit_failure );\ } While (0) # Define msgmax 8192 Struct msgbuf { Long mtype; Char mtext [msgmax]; }; Void echo_ser (INT msgid) { Struct msgbuf MSG; Memset (& MSG, 0, sizeof (MSG )); Int nrcv = 0; While (1) { If (nrcv = msgrcv (msgid, & MSG, msgmax, 1, 0) <0 ); Int pid = * (int *) msg. mtext ); Fputs (msg. mtext + 4, stdout ); MSG. mtype = PID; Msgsnd (msgid, & MSG, nrcv, 0 ); Memset (& MSG, 0, sizeof (MSG )); } } Int main (INT argc, char * argv []) { Int msgid; Msgid = msgget (1234, ipc_creat | 0666 ); If (msgid =-1) Err_exit ("msgget "); Echo_ser (msgid ); Return 0; } |
Echocli. c
C ++ code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
|
# Include <stdio. h> # Include <stdlib. h> # Include <sys/IPC. h> # Include <sys/msg. h> # Include <sys/types. h> # Include <unistd. h> # Include <errno. h> # Include <string. h># Define err_exit (m )\ Do {\ Perror (m );\ Exit (exit_failure );\ } While (0) # Define msgmax 8192 Struct msgbuf { Long mtype; Char mtext [msgmax]; }; Void echo_cli (INT msgid) { Int nrcv; Int pid = getpid (); Struct msgbuf MSG; Memset (& MSG, 0, sizeof (MSG )); MSG. mtype = 1; * (Int *) msg. mtext) = PID; While (fgets (msg. mtext + 4, msgmax, stdin )! = NULL) { If (msgsnd (msgid, & MSG, 4 + strlen (msg. mtext + 4), ipc_nowait) <0) Err_exit ("msgsnd "); Memset (msg. mtext + 4, 0, msgmax-4 ); If (nrcv = msgrcv (msgid, & MSG, msgmax, PID, 0) <0) Err_exit ("msgsnd "); Fputs (msg. mtext + 4, stdout ); Memset (msg. mtext + 4, 0, msgmax-4 ); } } Int main (INT argc, char * argv []) { Int msgid; Msgid = msgget (1234, 0 ); If (msgid =-1) Err_exit ("msgget "); Echo_cli (msgid ); Return 0; } |
The program logic is not complex, so let's just talk about it. Compile and run the server and open two more clients to see the normal echo output.
However, the above program has the risk of deadlocks. When multiple clients are opened and the queue is full, the server will block if it wants to write data, however, once the client sends data, it will block the waiting for the server to send a response, so it will not read the queue, that is, the message in the queue will not be reduced, and a deadlock will occur at this time, even if the server side writes data in non-blocking mode, the eagain error will be returned. In the program logic, we will also make it constantly try to write data, rather than roughly exit the process, this will lead to deadlocks.
To solve this problem, you can open several more private queues for service, as shown below:
That is, a client first creates a private message queue, and then sends the private message queue identifier and specific data to the shared queue. The server fork generates a sub-process, in this case, data can be reinjected to the queue based on the private queue identifier, and the client can read the data from the private queue to the callback.
Refer:
UNP