linux应用编程:进程间通信(二) 消息队列

一、概述

  • 消息队列与 FIFO 很相似,都是一个队列结构,都可以有多个进程往队列里面写信息,多个进程从队列中读取信息。但 FIFO 需要读、写的两端事先都打开,才能够开始信息传递工作。而消息队列可以事先往队列中写信息,需要时再打开读取信息。
  • 消息队列也分为Posix消息队列与System V消息队列,它们的区别有:
    ① 对Posⅸx消息队列的读总是返回最高优先级的最早消息,对 System V消息队列的读则可以返回任意指定优先级的消息。
    ① 当往一个空队列放置一个消息时,Posiⅸ消息队列允许产生一个信号或启动一个线程,System V消息队列则不提供类似机制。
  • 进程间通信多为System V消息队列
  • 从消息队列中读出消息,消息队列中对应的数据都会被删除。
  • 消息队列是消息的链表,存放在内存中,由内核维护。只有内核重启或人工删除消息队列时,该消息队列才会被删除。若不人工删除消息队列,消息队列会一直存在于系统中。
  • 消息队列不依据先进先出的原则。
    在这里插入图片描述

二、接口

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

/* @function 用于创建一个新的消息队列或访问一个已存在的消息队列
 * @param[in] key 通常由ftok创建,也可以指定为IPC_PRIVATE
 * @param[in] msgflg 读写权限值的组合。它还可以与IPC_CREAT或IPC_CREAT|IPC_EXCL按位或
 * @return 成功:非负标识符,失败:-1
 */
int msgget(key_t key, int msgflg);
//用例
int main(int argc, char *argv[])
{
	key_t key;
	int  msqid;
	
	key = ftok(".", 2020); // key 值
	
	// 创建消息队列
	msqid= msgget(key, IPC_CREAT|0666);
	
	return 0;
}
2.2 msgsnd
/* @function 往msqid标识符的消息队列放置一条消息
 * @param[in] msqid 消息队列标识
 * @param[in] msgp 待发送消息结构体的地址。消息结构通常如果  struct msgbuf
 * @param[in] msgsz 消息正文的长度 msgsz = sizeof(mymsg)-sizeof(long)
 * @param[in] msgflg 用于控制当前消息队列满或队列消息到达系统范围的限制时将要发生的事情
 * 			@arg:0 msgsnd() 调用阻塞直到条件满足为止。
 * 			@arg:IPC_NOWAIT  msgsnd() 调用阻塞直到条件满足为止。
 * @return 成功:0,失败:-1
 * note:如果 msgflg 指定了IPC_NOWAIT,当队列满或队列消息数已经超过系统的限制,msgsnd返回一个EAGAIN错误,不阻塞进程;
 * 		如果为0,则阻塞进程,直到满足下面三种情况:
 * 			① 具备存放新消息的空间;
 * 			② 由msqid标识的消息队列从系统中删除(这种情况下返回一个ETDRM错误)
 * 			③ 调用线程被某个捕获的信号所中断(这种情况下返回一个EINTR错误)。
 */
 /* message buffer for msgsnd and msgrcv calls */
struct msgbuf {
	long mtype;          /* type of message 必须大于0*/
	char msg_text[30];   /* message text */
}mymsg;
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
//用例
int main(int argc, char *argv[])
{
	key_t key;
	int  msqid;
	struct msgbuf mymsg;
	
	key = ftok(".", 2020); // key 值
	
	// 创建消息队列
	msqid= msgget(key, IPC_CREAT|0666);
	mymsg.mtype = 1;
	mymsg.msg_text[0] = 2;
	msgsnd(msqid, &mymsg, sizeof(mymsg)-sizeof(long), 0);
	return 0;
}
2.3 msgrcv
/* @function 往msqid标识符的消息队列读取一条消息
 * @param[in] msqid 消息队列标识
 * @param[out] msgp 读取消息的缓存区的地址
 * @param[in] msgsz 读取正文消息字节长度
 * @param[in] msgtyp 与上面struct msgbuf 结构中成员 mtype 有关
 * 		@arg msgtyp == 0, 返回队列中的第一个消息。
 * 		@arg msgtyp > 0, 返回队列中消息类型为 msgtyp 的第一个消息(常用)。
 * 		@arg msgtyp < 0, 返回队列中消息类型值小于或等于 msgtyp 绝对值的消息,如果这种消息有若干个,则取类型值最小的消息。
 * @param[in] msgflg 同msgsnd,但还可以指定MSG_ NOERROR:当所接收消息的真正数据部分大于 msgsz参数时,
 * 							如果设置了该位, msgrcvi函数就只是截短数据部分,而不返回错误,否则,ms_grev返回一个E2BIG错误。
 * @return 成功:读取信息的字节长度, 失败:-1
 * @note 成功返回时, msgrcv返回的是所接收消息中数据的字节数。它不包括通过msgp参数返回的长整数消息类型所需的几个字节。
 */
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
//用例
int main(int argc, char *argv[])
{
	key_t key;
	int  msqid;
	struct msgbuf mymsg;
	ssize_t rcv_len;
	
	key = ftok(".", 2020); // key 值
	
	// 打开消息队列
	msqid= msgget(key, IPC_CREAT|0666);
	rcv_len = msgrcv(msqid, &mymsg, sizeof(mymsg)-sizeof(long), 10);
	printf("rcv_len=%d, mymsg.msg_text=%s\n",rcv_len, mymsg.msg_text);
	return 0;
}
2.4 msgctl
struct msqid_ds {
	struct ipc_perm msg_perm;
	struct msg *msg_first;		/* first message on queue,unused  */
	struct msg *msg_last;		/* last message in queue,unused */
	__kernel_time_t msg_stime;	/* last msgsnd time */
	__kernel_time_t msg_rtime;	/* last msgrcv time */
	__kernel_time_t msg_ctime;	/* last change time */
	unsigned long  msg_lcbytes;	/* Reuse junk fields for 32 bit */
	unsigned long  msg_lqbytes;	/* ditto */
	unsigned short msg_cbytes;	/* current number of bytes on queue */
	unsigned short msg_qnum;	/* number of messages in queue */
	unsigned short msg_qbytes;	/* max number of bytes on queue */
	__kernel_ipc_pid_t msg_lspid;	/* pid of last msgsnd */
	__kernel_ipc_pid_t msg_lrpid;	/* last receive pid */
};

/* @function 操作并控制消息队列
 * @param[in] msqid 消息队列标识
 * @param[in] cmd 控制命令
 * 		@arg:IPC_RMID:删除由 msqid 指示的消息队列,将它从系统中删除并破坏相关数据结构。
 * 		@arg:IPC_STAT:将msqid 相关的数据结构中各个元素的当前值存入到由 buf 指向的结构中。
 * 						相当于,把消息队列的属性备份到 buf 里。
 * 		@arg:IPC_SET:将msqid 相关的数据结构中的元素设置为由 buf 指向的结构中的对应值。
 * 						相当于,消息队列原来的属性值清空,再由 buf 来替换。
 * @param[in] buf 消息队列结构缓存区
 * @return 成功:0,失败:-1
 */
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
//用例1
int main(int argc, char *argv[])
{
	key_t key;
	int  msqid;
	struct msgbuf mymsg;
	ssize_t rcv_len;
	
	key = ftok(".", 2020); // key 值
	
	// 打开消息队列
	msqid= msgget(key, IPC_CREAT|0666);
	rcv_len = msgrcv(msqid, &mymsg, sizeof(mymsg)-sizeof(long), 10);
	printf("rcv_len=%d, mymsg.msg_text=%s\n",rcv_len, mymsg.msg_text);
	msgctl(msqid, IPC_RMID, NULL);
	return 0;
}
//用例2
int main(int argc, char *argv[])
{
	key_t key;
	int  msqid;
	struct msgbuf mymsg;
	ssize_t rcv_len;
	struct msqid_ds msg_attr;
	
	key = ftok(".", 2020); // key 值
	
	// 打开消息队列
	msqid= msgget(key, IPC_CREAT|0666);
	rcv_len = msgrcv(msqid, &mymsg, sizeof(mymsg)-sizeof(long), 10);
	printf("rcv_len=%d, mymsg.msg_text=%s\n",rcv_len, mymsg.msg_text);
	
	msgctl(msqid, IPC_STAT, &msg_attr);
	printf("msg_stime=%d\n",msg_attr.msg_stime);
	printf("msg_rtime=%d\n",msg_attr.msg_rtime);
	printf("msg_ctime=%d\n",msg_attr.msg_ctime);
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值