Message queue for communication between linux processes

filename to key

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok (char*pathname, char proj);

It returns a key corresponding to the path pathname. This function does not operate directly on the message queue, but it is often called before calling msgget() to get the message queue descriptor.

message queue API

  There are four system message queue APIs, and several header files need to be included when using them:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

1)int msgget(key_t key, int msgflg)

The parameter key is a key value obtained by ftok; the msgflg parameter is some flag bits. This call returns the message queue descriptor corresponding to the key value.

The call will create a new message queue in the following two cases:

  • If there is no message queue corresponding to the key value, and msgflg contains the IPC_CREAT flag;
  • The key parameter is IPC_PRIVATE;

The parameter msgflg can be the following: IPC_CREAT, IPC_EXCL, IPC_NOWAIT or the OR of the three.

The call returns: successfully returns the message queue description word, otherwise returns -1.

Note: Setting the parameter key to the constant IPC_PRIVATE does not mean that other processes cannot access the message queue, but only means that a new message queue is about to be created.

2)int msgrcv(int msgid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflg);

This system call reads a message from the message queue represented by msgid and stores the message in the msgbuf structure pointed to by msgp.

msqid is the description word of the message queue; after the message is returned, it is stored at the address pointed to by msgp, msgsz specifies the length of the mtext member of msgbuf (that is, the length of the message content), and msgtyp is the message type requested to be read; the read message flag msgflg can be the following a constant or:

  • IPC_NOWAIT If there is no message that meets the condition, the call returns immediately, at this time, errno=ENOMSG
  • IPC_EXCEPT is used in conjunction with msgtyp>0 to return the first message in the queue whose type is not msgtyp
  • IPC_NOERROR If the content of the message in the queue that meets the condition is larger than the requested msgsz bytes, the message will be truncated, and the truncated part will be lost.

The msgrcv manual details which message in the message queue will be returned when the message type takes different values ​​(>0; <0; =0).

There are three conditions for msgrcv() to unblock:

  1. There are messages that meet the conditions in the message queue;
  2. The message queue represented by msqid is deleted;
  3. The process calling msgrcv() was interrupted by a signal;

The call returns: successfully returns the actual number of bytes of the read message, otherwise returns -1.

3)int msgsnd(int msqid, struct msgbuf *msgp, int msgsz, int msgflg);

Send a message to the message queue represented by msgid. The message to be sent is stored in the msgbuf structure pointed to by msgp, and the size of the message is specified by msgze.

For sending messages, the meaningful msgflg flag is IPC_NOWAIT, indicating whether msgsnd waits when the message queue does not have enough space for the message to send. There are two conditions that cause msgsnd() to wait:

  • The sum of the size of the current message and the number of bytes in the current message queue exceeds the total capacity of the message queue;
  • The number of messages in the current message queue (unit "piece") is not less than the total capacity of the message queue (unit "number of bytes"). At this time, although there are many messages in the message queue, they are basically only one byte.

There are three conditions for msgsnd() to unblock:

  1. If the above two conditions are not met, that is, there is room for the message in the message queue;
  2. The message queue represented by msqid is deleted;
  3. The process calling msgsnd() was interrupted by a signal;

调用返回:成功返回0,否则返回-1。

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

该系统调用对由msqid标识的消息队列执行cmd操作,共有三种cmd操作:IPC_STAT、IPC_SET 、IPC_RMID。

  1. IPC_STAT:该命令用来获取消息队列信息,返回的信息存贮在buf指向的msqid结构中;
  2. IPC_SET:该命令用来设置消息队列的属性,要设置的属性存储在buf指向的msqid结构中;可设置属性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes,同时,也影响msg_ctime成员。
  3. IPC_RMID:删除msqid标识的消息队列;

调用返回:成功返回0,否则返回-1。

例子:

TestQueueClient.cpp

#include "msgqueue.h"
#include <stdio.h>
#include <pthread.h>
int msgid = 0;
IpcMsgQueue msgQueue;
void* Receive(void* arg){
	char buff[1024] = {0};
	fflush(stdout);
	msgQueue.ReceiveMessage(msgid,buff,_SERVER_);
	printf("Server#%s\n",buff);
	return 0;
}

void* Send(void* arg){
	char buff[1024] = {0};
	printf("Client#");
	fflush(stdout);
	ssize_t s = read(1,buff,sizeof(buff));
	buff[s-1] = 0;
	msgQueue.SendMessage(msgid,buff,_CLIENT_);
	return 0;
}

int main(){
	key_t key = ftok(PATHNAME,PROJNAME);
	if(key < 0){
		perror("ftok");
		return 1;
	}
	msgid = msgQueue.GetMessage(key);
	pthread_t c1,c2;
	for(int i=0; i<10; ++i){
		pthread_create(&c1,NULL,Send,NULL);
		pthread_create(&c2,NULL,Receive,NULL);
		pthread_join(c1,NULL);
		pthread_join(c2,NULL);
	}
	return 0;
}

TestQueueServer.cpp

#include "msgqueue.h"
#include <stdio.h>
#include <pthread.h>
int msgid = 0;
IpcMsgQueue msgQueue;
void* Receive(void* arg){
	char buff[1024] = {0};
	msgQueue.ReceiveMessage(msgid,buff,_CLIENT_);
	printf("Client#%s\n",buff);
	return 0;
}

void* Send(void* arg){
	char buff[1024] = {0};
	printf("Server#");
	fflush(stdout);
	ssize_t s = read(1,buff,sizeof(buff));
	buff[s-1] = 0;
	msgQueue.SendMessage(msgid,buff,_SERVER_);
	return 0;
}

int main(){
	key_t key = ftok(PATHNAME,PROJNAME);
	if(key < 0){
		perror("ftok");
		return 1;
	}
	msgid = msgQueue.CreateMessage(key);
	pthread_t c1,c2;
	for(int i=0; i<10; ++i){
		pthread_create(&c1,NULL,Send,NULL);
		pthread_create(&c2,NULL,Receive,NULL);
		pthread_join(c1,NULL);
		pthread_join(c2,NULL);
	}
	msgQueue.DestoryMessage(msgid);
	return 0;
}

msgqueue.h

#ifndef __PUB_MSGQUEUE_H__
#define __PUB_MSGQUEUE_H__
/*
	desc:进程间通讯--消息队列
	writer:Lake
*/
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include "../Log.h"

#define _SERVER_ 1
#define _CLIENT_ 2
#define PATHNAME "/"
#define PROJNAME 0

//消息结构体
struct IpcMsgbuf
{
        long mtype;      //消息类型,由用户自定义
        char mtext[1024];//发送的消息(长度、类型可以自行指定)
};
//进程间消息队列通讯类
class IpcMsgQueue
{
	public:
		IpcMsgQueue()
		{
			
		}
		virtual ~IpcMsgQueue()
		{
			
		}
	public:
		//创建与打开消息队列公共函数
		int MessageCommon(key_t key,int flag);
		//创建全新的消息队列(服务端)
		int CreateMessage(key_t qid);
		//打开已有的消息队列(客户端)
		int GetMessage(key_t qid);
		//发送消息
		void SendMessage(int msgid,const char* msg,int who);
		//接收消息
		void ReceiveMessage(int msgid,char* msg,int who);
		//消息队列的删除
		void DestoryMessage(int msgid);
};

#endif

msgqueue.cpp

#include "msgqueue.h"

//创建与打开消息队列公共函数
int IpcMsgQueue::MessageCommon(key_t key,int flag)
{
    int ret = 0;
    if((ret=msgget(key,flag))==-1){
        //LOG (LOG_ERROR, __FILE__, __LINE__, "MessageCommon--error[%s]",strerror(errno));
    }
    return ret;
}
//创建全新的消息队列(服务端)
int IpcMsgQueue::CreateMessage(key_t qid)
{
    //消息队列也是具有权限结构的,因此在创建时给666权限
    return MessageCommon(qid,IPC_CREAT|IPC_EXCL|0666);
}
//打开已有的消息队列(客户端)
int IpcMsgQueue::GetMessage(key_t qid)
{
    return MessageCommon(qid,IPC_CREAT);
}
//发送消息
void IpcMsgQueue::SendMessage(int msgid,const char* msg,int who)
{
    IpcMsgbuf buf;
    buf.mtype = who;                //消息类型
    strcpy(buf.mtext,msg);        //消息内容
    if(msgsnd(msgid,&buf,sizeof(buf.mtext),0) == -1){
    	//LOG (LOG_ERROR, __FILE__, __LINE__, "SendMessage--error[%s]",strerror(errno));
        DestoryMessage(msgid);
    }
}
//接收消息
void IpcMsgQueue::ReceiveMessage(int msgid,char* msg,int who)
{
    IpcMsgbuf buf;
    if(msgrcv(msgid,&buf,sizeof(buf.mtext),who,0)==-1){
    	//LOG (LOG_ERROR, __FILE__, __LINE__, "SendMessage--error[%s]",strerror(errno));
        DestoryMessage(msgid);
    }
    strcpy(msg,buf.mtext);
}
//消息队列的删除
void IpcMsgQueue::DestoryMessage(int msgid)
{
    if(msgctl(msgid,IPC_RMID,NULL) == -1){
        //LOG (LOG_ERROR, __FILE__, __LINE__, "DestoryMessage--error[%s]",strerror(errno));
    }
}

Makefile

INCLUDE = -I ../ -I ../../
LIB = -lpthread
CLIENTOBJS = TestQueueClient.cpp ../msgqueue.o
SERVEROBJS = TestQueueServer.cpp ../msgqueue.o
G = g++
CFLAGS = -Wall -O -g

all:Client Server

Client:$(CLIENTOBJS)
	$(G) -o Client $(CLIENTOBJS) $(INCLUDE) $(LIB)
Server:$(SERVEROBJS)
	$(G) -o Server $(SERVEROBJS) $(INCLUDE) $(LIB)
msgqueue.o:
	$(G) $(CFLAGS) -c  $(INCLUDE) -o msgqueue.o msgqueue.cpp
clean:
	rm -f Client Server
	rm -f ../*.o
Makefile, TestQueueClient.cpp, TestQueueServer.cpp files, put them in the test folder of the same msgqueue.h, msgqueue.cpp directory, and then the compilation test can be completed.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324772608&siteId=291194637