Linux IPC interprocess communication -- message queue

Posted by zako234 on Sat, 08 Jan 2022 10:03:17 +0100

Message queue is the connection table of messages, which is stored in the kernel. This example mainly realizes inter process communication in the way of message queue. After receiving the message, the receiving end immediately forwards it to the sending end; After sending a message, the sender immediately monitors the message fed back by the receiver to realize a two-way communication example.

1, Example

Sender client c

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

#define MSG_FILE "server.c"  
#define BUFFER 255  
#define PERM S_IRUSR|S_IWUSR

struct msgtype {  
	long mtype;  
	char buffer[BUFFER];  
}; 

int main(int argc,char **argv)  
{  
	struct msgtype msg;  
	key_t key;  
	int msgid;
	struct msqid_ds msqid;


	if((key = ftok(MSG_FILE, 'a')) == -1) {  
		fprintf(stderr,"Creat Key Error:%s\a\n",strerror(errno));  
		exit(-1);  
	}

	if((msgid = msgget(key, PERM | IPC_CREAT))==-1)  
	{  
		fprintf(stderr,"Creat Message Error:%s\a\n",strerror(errno));  
		exit(-1);  
	}

	printf("PID=%d\n", getpid());

	while(1) {
		printf("Please in put the sending msg:");
		if((fgets(msg.buffer, BUFFER, stdin)) == NULL){
			printf("No message, terminal msg sending\n");
			exit(1);
		}
		msg.mtype=1;
		// client send.
		msgsnd(msgid, &msg, sizeof(struct msgtype), 0);

		memset(&msg,'\0',sizeof(struct msgtype));
		sleep(1);
		// client recive.
		msgrcv(msgid, &msg, sizeof(struct msgtype), 2, 0);
		fprintf(stderr,"Client receive:[ID=%ld] msg=%s\n", msg.mtype, msg.buffer);
		msgctl(msgid, IPC_STAT, &msqid);
		printf("last-msgsnd pid=%d\nlast-msgrcv pid=%d\n", msqid.msg_lspid, msqid.msg_lrpid);
	}

	// remove msg in system and delete all data in buffer.
	msgctl(msgid, IPC_RMID, NULL);
 
	exit(0);  
}

Receiver server c

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

#define MSG_FILE "server.c"  
#define BUFFSIZE 255  
#define PERM S_IRUSR|S_IWUSR  

struct msgtype {  
	long mtype;  
	char buffer[BUFFSIZE];  
};


int main(void) {  
	struct msgtype msg;  
	key_t key;  
	int msgid;  

	if((key = ftok(MSG_FILE, 'a')) == -1) {  
		fprintf(stderr,"Creat Key Error %s\a\n",strerror(errno));  
		exit(-1);  
	}

	if((msgid = msgget(key, PERM|IPC_CREAT)) == -1) {  
		fprintf(stderr,"Creat Message Error:%s\a\n",strerror(errno));  
		exit(-1);  
	}  
	printf("PID=%d\n", getpid());
	while(1)
	{
		// server receive.
		msgrcv(msgid, &msg, sizeof(struct msgtype), 1, 0);  
		fprintf(stderr,"Server Receive:[ID=%ld] %s\n", msg.mtype, msg.buffer);
		msg.mtype = 2;
		// server send.
		printf("send:%s\n", msg.buffer);
		msgsnd(msgid, &msg, sizeof(struct msgtype), 0);
	}  
	exit(0);  
}

Operation results:

receiving end

PID=141798
Server Receive:[ID=1] hello

send:hello

Server Receive:[ID=1] hello

send:hello

Server Receive:[ID=1] world

send:world

Sender

PID=141800
Please in put the sending msg:hello
Client receive:[ID=2] msg=hello

last-msgsnd pid=141798
 last-msgrcv pid=141800
Please in put the sending msg:world
Client receive:[ID=2] msg=world

last-msgsnd pid=141798
 last-msgrcv pid=141800

2, Interface function analysis

key_t ftok(const char *path, int id);

IPC structures (message queue, semaphore and shared memory) in the kernel have a unique non negative integer identifier, which is generated by ftok function. Path, you must reference an existing file. When generating a key, only the lower 8 bits of the id parameter are used.

int msgget (key_t key, int msgflg);

It is used to create a new queue or open an existing queue. For example, specify the key as IPC_PRIVATE means to reference an existing queue; The key generated by ftok indicates the creation of a new queue. msgflg has three:
        IPC_ Create (create if the key does not exist);
        IPC_EXCL (if the key exists, failure is returned);
        IPC_NOWAIT (return error without waiting)

int msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg);

msqid indicates the id value returned by msget; The msgp pointer points to the user-defined data buffer sent; msgsz, specify the length of the transmission data buffer; msgflag can be specified as IPC_NOWAIT means that if the queue is full, EAGAIN will be returned immediately. If IPC is not specified_ Nowait, it will block until there is space for the message to be sent, or the queue is deleted from the system (EIDRM error is returned), or a signal is captured and returned from the signal handler (EINTR error is returned).

ssize_t msgrcv (int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

msqid, msgp, msgsz and msgflag are the same as those described in the msgsnd interface above. msgtyp specifies the message value returned after the queue overflow or underflow specified by msgflg. msgtyp classification:
msgtyp==0, return the first message in the queue;
Msgtyp > 0, return the message with message type msgtyp in the queue;
Msgtyp < 0, return the message whose message type is less than the absolute value of msgtyp in the queue. If there are multiple messages, take the one with the smallest type value.

int msgctl (int msqid, int cmd, struct msqid_ds *buf);        

Similar to the ioctl function, the first parameter msqid is the return value of msgget, and the second cmd is as follows:
        IPC_SATA, get msqid of queue_ DS structure information and stored in buf;
        IPC_SET, related msqid in buf_ DS related data is set to the msqid of the queue_ In DS;
        IPC_RMID, which deletes the message queue and the data still in the queue from the system. The deletion takes effect immediately. If the process using the queue returns an EIDRM error when it operates on the queue again;

Topics: C Linux ipc