系统编程之进程间的消息队列通信(5)
系列文章目录
目录
一、消息队列
1、消息队列的原理
- 消息队列是一种先进先出的队列型数据结构,实际上是系统内核中的一个内部链表。消息被顺序插入队列中,其中发送进程将消息添加到队列末尾,接受进程从队列头读取消息。
- 多个进程可同时向一个消息队列发送消息,也可以同时从一个消息队列中接收消息。发送进程把消息发送到队列尾部,接受进程从消息队列头部读取消息,消息一旦被读出就从队列中删除。
查看消息队列: ipcs -q
删除消息队列: ipcrm -q 消息队列的ID号
2、结构体定义
消息队列中消息本身由消息类型和消息数据组成,通常使用如下结构。
struct msg
{
long mtype; //消息类型
char mtext[1]; //真实的信息
}
3、相关的接口函数
(1)申请创建消息队列
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
返回值:成功 返回消息队列的ID
失败 -1
key :键值
msgflg
IPC_CREAT :
如果消息队列对象不存在,则创建之,否则则进行打开操作;
IPC_EXCL:
和IPC_CREAT 一起使用(用”|”连接),如果消息对象不存在则创建之,否则产生一个错误并返回。如果单独使用IPC_CREAT 标志,msgget()函数要么返回一个已经存在的消息队列对象的标识符,要么返回一个新建立的消息队列对象的标识符。
(2)通过消息队列收发信息
发送信息:
把发送的信息打包成结构体
struct msg
{
//消息类型
//真实的信息
}
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
返回值:成功 0 失败 -1
参数:msgp --》你要发送的信息
msgsz --》你打算发送多少字节的数据
msgflg --》默认设置为0
msgsnd(id,"hello",5,0);
msgsnd(id,"hehe",4,0);
msgsnd(id,"china",5,0); //错误的写法,原因信息没有打包成结构体(结构体包含了消息的类型)
接收信息:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
返回值:成功返回接收的字节数 失败 -1
参数:msgtyp(重点,重点,重点) --》你要接收的消息类型
其它参数跟msgsnd类似
(3)删除,获取,设置消息队列的属性
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
返回值:成功0 失败返回-1
参数--》msgqid:是消息队列对象的标识符。
cmd:消息队列进行的操作:
IPC_STAT:取出系统保存的消息队列的msqid_ds 数据,并将其存入参数buf 指向的msqid_ds 结构中。
IPC_SET:设定消息队列的msqid_ds 数据中的msg_perm 成员。设定的值由buf 指向的msqid_ds结构给出。
IPC_EMID:将队列从系统内核中删除。
IPC_STAT:将信息从与msqid关联的内核数据结构复制到buf指向的msqid_ds结构中。调用方必须对消息队列具有读取权限
struct msqid_ds {
struct ipc_perm msg_perm; /* Ownership and permissions */
time_t msg_stime; /* Time of last msgsnd(2) */
time_t msg_rtime; /* Time of last msgrcv(2) */
time_t msg_ctime; /* Time of last change */
unsigned long __msg_cbytes; /* Current number of bytes in queue (nonstandard) */
msgqnum_t msg_qnum; /* Current number of messages in queue */
msglen_t msg_qbytes; /* Maximum number of bytes allowed in queue */
pid_t msg_lspid; /* PID of last msgsnd(2) */
pid_t msg_lrpid; /* PID of last msgrcv(2) */};
4、使用实例
(1)发送端代码
#include "myhead.h"
//自定义一个结构体存放要发送的信息和类型
struct msg
{
long msgtype; //消息类型
char msgdata[50]; //存放真实信息
};
int main()
{
int msgid;
//申请创建消息队列
msgid=msgget(74545,IPC_CREAT|IPC_EXCL|0777);
if(msgid==-1)
{
if(errno==EEXIST)
{
msgid=msgget(74545,0777);
}
else
{
perror("创建失败!\n");
return -1;
}
}
//组包发送信息给接收端
struct msg msg1;
bzero(&msg1,sizeof(msg1));
msg1.msgtype=999;
strcpy(msg1.msgdata,"hello");
msgsnd(msgid,&msg1,sizeof(msg1),0);
struct msg msg2;
bzero(&msg2,sizeof(msg2));
msg2.msgtype=999;
strcpy(msg2.msgdata,"world");
msgsnd(msgid,&msg2,sizeof(msg2),0);
struct msg msg3;
bzero(&msg3,sizeof(msg3));
msg3.msgtype=999;
strcpy(msg3.msgdata,"gec");
msgsnd(msgid,&msg3,sizeof(msg3),0);
}
(2)接收端代码
#include "myhead.h"
//自定义一个结构体存放要发送的信息和类型
struct msg
{
long msgtype; //消息类型
char msgdata[50]; //存放真实信息
};
int main()
{
int msgid;
//申请创建消息队列
msgid=msgget(74545,IPC_CREAT|IPC_EXCL|0777);
if(msgid==-1)
{
if(errno==EEXIST)
{
msgid=msgget(74545,0777);
}
else
{
perror("创建失败!\n");
return -1;
}
}
//接收发送端发送过来的信息
struct msg msg1;
bzero(&msg1,sizeof(msg1));
//msgrcv(msgid,&msg1,sizeof(msg1),777,0);
msgrcv(msgid,&msg1,sizeof(msg1),999,0);
printf("接收的信息:%s\n",msg1.msgdata);
bzero(&msg1,sizeof(msg1));
msgrcv(msgid,&msg1,sizeof(msg1),999,0);
printf("接收的信息:%s\n",msg1.msgdata);
bzero(&msg1,sizeof(msg1));
msgrcv(msgid,&msg1,sizeof(msg1),999,0);
printf("接收的信息:%s\n",msg1.msgdata);
}
总结
以上就是本文要介绍的内容,本文仅仅简单介绍了消息队列的原理和使用实例