Linux下进程间通信 之 消息队列

先看在项目中的实例  

  • 定义使用接口

(1)定义消息队列的大小

#define MAX_QUEUEMSGNUM         (64)                /*消息队列的消息数*/
#define MAX_QUEUEMSGSIZE        (256)               /*消息队列的消息大小*/


/*定义消息队列的结构体*/
typedef struct 
{
	int  wordMsg1st;
	int  wordMsg2nd;
	int  wordMsg3rd;
	int  wordMsg4th;
}t_queueMsg;

typedef struct msgBufStr
{
	int       mtype;                      /*消息类型必须大于0*/
	char     mtext[MAX_QUEUEMSGSIZE];
}t_msgBuf;

(2)获取创建消息队列的keyID

/*获取创建消息队列的keyID,各进程约定以/home/文件夹下的szName文件来产生key*/
int osGetKeyID(char *szName)
{
	key_t keyID;
	keyID=ftok("/home/",atol(szName));
	return keyID;
}

(3)创建消息队列szName:请取ASCII吗

bool osCreateQueue(char *szName,int queueNum,int queueSize,int dwFlag, unsigned int *queueID)
{
	int keyID;
	unsigned ine tempID;
	struct msqid_ds msg_info;

	keyID = osGetKeyID(szName);
	if(0 > (tempID = msgget(keyID, 0666|IPC_CREAT))) 
	{ 
        printf("msgget error\n"); 
        return false;
	} 

	/*获取消息队列的属性*/
	if (!msgctl(tempID, IPC_STAT, &msg_info))
	{
		msgctl(tempID, IPC_RMID, NULL);/*删除队列*/
		return false;
	}

	/*根据入参调整消息队列的属性*/
	msg_info.msg_qbytes = queueNum * queueSize;/*消息队列的最大长度*/
	if (!msgctl(tempID, IPC_SET, &msg_info))/*调整队列属性失败*/
	{
		msgctl(tempID, IPC_RMID, NULL);/*删除队列*/
		return false;
	}

	*udwQueueID = tempID;

	return true;
}

(4)发送消息

int osQueueSndMsg(unsigned queueID, T_MSGBUF *msg, int dwFlag)
{
	int res;
	int msgSize = MAX_QUEUEMSGSIZE;
	res = msgsnd(queueID, msg, msgSize, dwFlag);

	if(SUCCESS != res)
	{
		fprintf(stderr, "msgsnd failed \n");
		return res;
	}
	//printf("msgsnd lenth:%d\n", sizeof(QUEUE_MESSAGE));

	return res;
}

(5)接收消息

int osQueueRcvMsg(unsigned int queueID, int msgtype, T_MSGBUF *msg, int dwFlag)
{
	int rcvLen;
	int queueSize = MAX_QUEUEMSGSIZE;

	rcvLen = msgrcv(queueID, msg, queueSize, msgtype, dwFlag);
	if(rcvLen < 0)
	{
		return rcvLen;
	}

	if(rcvLen < queueSize)
	{
		//printf("rcvmsg rcvLen < dwQueueSize revlen:%d\n", rcvLen);
		return false;
	}

	//printf("rcvmsg rcvLen:%d\n", rcvLen);
	return rcvLen;
}

(6)删除消息队列

int osQueueDelete(unsigned int queueID)
{
    return msgctl(queueID, IPC_RMID, NULL);
}
  • 使用接口

(1)根据业务需要创建A进程的消息队列

#define QueueName 100011 // 根据业务定义

char queueName[32];
unsingned int queueID = 0;

memset(queueName, 0x0, sizeof(queueName));
sprintf(queueName,"%d", QueueName);

int ret = osCreateQueue(queueName, MAX_QUEUEMSGNUM, MAX_QUEUEMSGSIZE, 0, &queueID);
if(ret == false)
{
    printf("create %s queueID fail \n", queueName);
    return;
}

(2)向A进程发送消息

boot sndMsgToProcA(unsigned int queueID, int msgtype)
{
    int res = 0;

    t_msgBuf stMsg;
    t_queueMsg message;
    memset(&stMsg,0x0,sizeof(t_msgBuf));
    memset(&message,0x0,sizeof(t_queueMsg));

    message.wordMsg1st = msgtype;
    stMSG.mtype = APP_MSG_TYPE; // 自定义消息类型
    memcpy(stMSG.mtext, &message, sizeof(t_queueMsg));
    
    res = osQueueSndMsg(queueID, &stMSG, IPC_NOWAIT);
    if(!res)
    {
        printf("send data error\n");
        return false;
    }
    
    return true;
}

=========================================================================

以下概念的叙述为转载:

linux基础——linux进程间通信(IPC)机制总结_千里之行,始于足下-优快云博客_linux 进程间通信

        消息队列是内核地址空间中的内部链表,通过linux内核在各个进程直接传递内容,消息顺序

地发送到消息队列中,并以几种不同的方式从队列中获得,每个消息队列可以用 IPC标识符 唯一

地进行识别。内核中的消息队列是通过IPC的标识符来区别,不同的消息队列直接是相互独立的。

每个消息队列中的消息,又构成一个 独立的链表。

        消息队列克服了信号承载信息量少,管道只能承载无格式字符流。 

(1)消息缓冲区结构: 

// 头文件
#include <sys/types.h> 
#include <sys/stat.h> 
#include <sys/msg.h> 

// 在结构中有两个成员: 
// mtype为消息类型,用户可以给某个消息设定类型,可以在消息队列中正确地发送和接受自己的消息
// mtext为消息数据,采用柔性数组,用户可以重新定义msgbuf结构。例如:
struct msgbuf{
    long mtype;
    char mtext[1];//柔性数组
}

用户不可随意定义msgbuf结构,因为在linux中消息的大小有限制,在linux/msg.h中定义如下:

#define MSGMAX 8192

消息总的大小不能超过8192个字节,包括mtype成员(4个字节)。

(2)msqid_ds内核数据结构。

struct msgid_ds{
    struct ipc_perm msg_perm{   
        time_t msg_stime;   
        time_t msg_rtime;   
        time_t msg_ctime;   
        unsigned long _msg_cbuyes;    
        .......... 
    }  
};

        Linux内核中,每个消息队列都维护一个结构体,此结构体保存着消息队列当前状态信息,该

结构体在头文件linux/msg.h中定义。

(3)ipc_perm内核数据结构

struct ipc_perm{
  key_t key;
  uid_t uid;
  gid_t gid;
  .......
};

        结构体ipc_perm保存着消息队列的一些重要的信息,比如说消息队列关联的键值,消息队列

的用户id组id等。它定义在头文件linux/ipc.h中。

常用函数:

        系统建立IPC通讯 (消息队列、信号量和共享内存) 时必须指定一个ID值。通常情况下,该

id值通过ftok函数得到。 

        关于ftok函数,可以看这篇博文:

         转载:ftok()函数深度解析_u013485792的专栏-优快云博客_ftok函数作用

消息队列的本质

        Linux的消息队列(queue)实质上是一个链表,它有消息队列标识符(queue ID)。 msgget创建

一个新队列或打开一个存在的队列;msgsnd向队列末端添加一条新消息;msgrcv从队列中取消

息, 取消息是不一定遵循先进先出的, 也可以按消息的类型字段取消息

消息队列与命名管道的比较

        消息队列跟命名管道有不少的相同之处,通过与命名管道一样,消息队列进行通信的进程可

以是不相关的进程,同时它们都是通过发送和接收的方式来传递数据的。在命名管道中,发送数据

用write,接收数据用read,则在消息队列中,发送数据用msgsnd,接收数据用msgrcv。而且它们

对每个数据都有一个最大长度的限制

        与命名管道相比,消息队列的优势在于:

        1、消息队列可以独立于发送和接收进程而存在,从而消除了在同步命名管道的打开和关闭

              时可能产生的困难。

        2、同时通过发送消息还可以避免命名管道的同步和阻塞问题,不需要由进程自己来提供同步

             方法。

        3、接收程序可以通过消息类型有选择地接收数据,而不是像命名管道中那样只能默认地接收

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值