一、概念
消息队列,是消息的链表,存放在内核中,一个消息队列由一个标识符(队列ID)来标识。
二、特点
*消息队列是面向记录的,其中的消息
具有特定的格式以及特定的优先级
*消息队列独立于发送和接收进程,进程
终止
时,
消息队列及其内容仍存在
*消息队列可以实现消息的随机查询,消息不
一定要先进先出的次序读取,也可以按消息的类型读取。
三、相关函数
1.int msgget(key_t key, int msgflg);
功能:
创建或打开消息队列,
参数:
key:
和消息队列关联的
key
值
msgflg
:是一个权限标志,表示消息队列的访问权限,它与文件的访问权限一样。
msgflg可以与IPC_CREAT做或操作
,表示当key
所命名的消息队列不存在时创建一个消息队列,如果
key
所命名的消息队列存在时,
IPC_CREAT
标志会被忽略,而只返回一个标识符。
返回值:
成功返回队列
ID
,失败则返回
‐1
,
在以下两种情况下,msgget将创建一个新的消息队列:
1、如果没有与键值
key
相对应的消息队列,并且
flag
中包含了
IPC_CREAT
标志
2、key
参数为
IPC_PRIVATE
示例:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
int main()
{
int msgID;
msgID = msgget(IPC_PRIVATE,0755);
if(msgID == -1)
{
printf("消息队列创建不成功\n");
perror("msgget");
return -1;
}
else
{
printf("消息队列创建成功\n");
system("ipcs -q");//查看队列信息
}
return 0;
}
运行结果:
![](https://i-blog.csdnimg.cn/direct/554df4f7ccf54d46aaff96ef2ca2a916.png)
2.int msgctl(int msqid, int cmd, struct msqid_ds *buf);
功能:
控制消息队列
参数:
msqid
:消息队列的队列
ID
cmd
:
1.IPC_STAT:把
msgid_ds
结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds
的值。
2.IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为
msgid_ds
结构中给出的值IPC_RMID:删除消息队列
buf
:是指向
msgid_ds
结构的指针,它指向消息队列模式和访问权限的结构
返回值:
成功:
0
失败:
‐1
示例:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
int main()
{
int msgID,msgrnt;
msgID = msgget(IPC_PRIVATE,0755);
if(msgID == -1)
{
printf("消息队列创建不成功\n");
perror("msgget");
return -1;
}
else
{
printf("消息队列创建成功\n");
system("ipcs -q");//查看队列信息
}
msgrnt = msgctl(msgID,IPC_RMID,NULL);
if(msgrnt == -1)
{
printf("消息队列控制函数>删除失败\n");
perror("msgctl");
return -2;
}
else
{
printf("消息队列控制函数成功\n");
system("ipcs -q");
}
return 0;
}
运行结果:
![](https://i-blog.csdnimg.cn/direct/80127fe7bec44f338114098dd1c3948f.png)
3.int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:
读取消息
参数:
msgid:
消息队列的
ID
msgp:
指向消息的指针,常用结构体
msgbuf
如下:
struct msgbuf
{
long mtype; //消息类型
char mtext[N]; //消息正文
}
msgsz:
发送的消息正文你的字节数
msgflag:
IPC_NOWAIT: 消息没有发送完成函数也会立即返回
0: 知道发送完成函数才返回
返回值:
成功:
0
失败:
‐1
4.ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
功能:
从一个消息队列中获取消息
参数:
msgid:
消息队列的
ID
msgp:
要接收消息的缓冲区
msgsz:
要接收的消息的字节数
msgtype:
等于0: 接收消息队列中第一个消息
大于0
:接收消息队列中第一个类型为
msgtyp
的消息
小于0
:接收消息队列中类型值不大于
msgtyp
的绝对值且类型值又最小的消息。
flag:
0:若无消息函数一直阻塞
IPC_NOWAIT:若没有消息,进程会立即返回
ENOMSG
。
返回值:
成功:接收到的消息
i
长度
出错:
‐1
示例:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
struct msgbuf
{
long mtype; //消息类型
char mtext[128]; //消息正文
};
int main()
{
int msgID,msgrnt;
struct msgbuf readBuf,writeBuf;
int readRnt;
msgID = msgget(IPC_PRIVATE,0755);
if(msgID == -1)
{
printf("消息队列创建不成功\n");
perror("msgget");
return -1;
}
else
{
printf("消息队列创建成功,ID号为:%d\n",msgID);
}
//初始化结构体
writeBuf.mtype = 100; //消息类型
printf("请向%d号队列输入数据\n",msgID);
memset(writeBuf.mtext,0,128);
memset(readBuf.mtext,0,128);
fgets(writeBuf.mtext,128,stdin);
//向队列发送数据
msgsnd(msgID,(void *)&writeBuf,strlen(writeBuf.mtext),0);
//从队列读取数据
readRnt = msgrcv(msgID,(void *)&readBuf,128,100,0);
printf("从%d号消息队列接收到%d个数据,内容为:%s",msgID,readRnt,readBuf.mtext);
return 0;
}
运行结果:
![](https://i-blog.csdnimg.cn/direct/f15755ee4fd548748613ef8d9e24f9d9.png)
PS:消息队列的数据被读了之后,字节数会清除,但是队列中的内核节点依旧存在
![](https://i-blog.csdnimg.cn/direct/941198b19da145d79598186a0db9ca95.png)
5.ftok函数
key_t ftok( char * fname, int id )
功能:
系统建立
IPC
通讯(如消息队列、共享内存时)必须指定一个
ID
值。通常情况下,该
id
值通过
ftok
函数得到。
参数:
fname:
就时你指定的文件名
(
该文件必须是存在而且可以访问的
)
。
id:
是子序号, 虽然为
int
,但是只有
8
个比特被使用
(0‐255)
。
返回值:
当成功执行的时候,一个
key_t
值将会被返回,否则
‐1
被返回。
示例(半双工):
msg_read.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
struct msgbuf
{
long mtype; //消息类型
char mtext[128]; //消息正文
};
int main()
{
int msgID,msgrnt;
struct msgbuf readBuf;
int readRnt;
key_t key;
key = ftok("a.c",1);
msgID = msgget(key,IPC_CREAT|0755);
if(msgID == -1)
{
printf("消息队列创建不成功\n");
perror("msgget");
return -1;
}
else
{
while(1)
{
memset(readBuf.mtext,0,128);
//从队列读取数据
readRnt = msgrcv(msgID,(void *)&readBuf,128,100,0);
printf("从%d号消息队列接收到%d个数据,内容为:%s",msgID,readRnt,readBuf.mtext);
}
}
return 0;
}
msg_write.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
struct msgbuf
{
long mtype; //消息类型
char mtext[128]; //消息正文
};
int main()
{
int msgID,msgrnt;
struct msgbuf writeBuf;
key_t key;
key = ftok("a.c",1);
msgID = msgget(key,IPC_CREAT|0755);
if(msgID == -1)
{
printf("消息队列创建不成功\n");
perror("msgget");
return -1;
}
else
{
printf("消息队列创建成功,ID号为:%d\n",msgID);
}
//初始化结构体
writeBuf.mtype = 100; //消息类型
while(1)
{
printf("请向%d号队列输入数据\n",msgID);
memset(writeBuf.mtext,0,128);
fgets(writeBuf.mtext,128,stdin);
//向队列发送数据
msgsnd(msgID,(void *)&writeBuf,strlen(writeBuf.mtext),0);
}
return 0;
}
运行结果:
![](https://i-blog.csdnimg.cn/direct/dfc84baca0f549b99f67fbac671f4793.png)
示例(全双工):
msg_client.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include<sys/types.h>
#include <sys/wait.h>
struct msgbuf
{
long mtype; //消息类型
char mtext[128]; //消息正文
};
int main()
{
int msgID,msgrnt;
struct msgbuf readBuf,writeBuf;
int readRnt;
pid_t pid;
key_t key;
key = ftok("a.c",1);
msgID = msgget(key,IPC_CREAT|0755);
if(msgID == -1)
{
printf("消息队列创建不成功\n");
perror("msgget");
return -1;
}
else
{
printf("消息队列创建成功,ID号为:%d\n",msgID);
}
pid = fork();
if(pid == -1)
{
printf("fork fail!\n");
perror("fork");
return -2;
}
writeBuf.mtype = 200; //消息类型
if(pid >0)//客户端父进程写200
{
while(1)
{
printf("请向服务端%d号队列输入数据\n",msgID);
memset(writeBuf.mtext,0,128);
fgets(writeBuf.mtext,128,stdin);
//向队列发送数据
msgsnd(msgID,(void *)&writeBuf,strlen(writeBuf.mtext),0);
}
}
if(pid == 0)//客户端子进程读100
{
while(1)
{
memset(readBuf.mtext,0,128);
//从队列读取数据
readRnt = msgrcv(msgID,(void *)&readBuf,128,100,0);
printf("从%d号消息队列接收到%d个数据,内容为:%s",msgID,readRnt,readBuf.mtext);
}
}
return 0;
}
msg_service.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct msgbuf
{
long mtype; //消息类型
char mtext[128]; //消息正文
};
int main()
{
int msgID,msgrnt;
struct msgbuf readBuf,writeBuf;
int readRnt;
pid_t pid;
key_t key;
key = ftok("a.c",1);
msgID = msgget(key,IPC_CREAT|0755);
if(msgID == -1)
{
printf("消息队列创建不成功\n");
perror("msgget");
return -1;
}
else
{
printf("消息队列创建成功,ID号为:%d\n",msgID);
}
pid = fork();
if(pid == -1)
{
printf("fork fail!\n");
perror("fork");
return -2;
}
writeBuf.mtype = 100; //消息类型
if(pid == 0)//服务器子进程写100
{
while(1)
{
//初始化结构体
printf("请向客户端%d号队列输入数据\n",msgID);
memset(writeBuf.mtext,0,128);
fgets(writeBuf.mtext,128,stdin);
msgsnd(msgID,(void *)&writeBuf,strlen(writeBuf.mtext),0);
}
}
if(pid > 0)//服务器父进程读200
{
while(1)
{
memset(readBuf.mtext,0,128);
//从队列读取数据
readRnt = msgrcv(msgID,(void *)&readBuf,128,200,0);
printf("从%d号消息队列接收到%d个数据,内容为:%s",msgID,readRnt,readBuf.mtext);
}
}
return 0;
}
运行结果:
![](https://i-blog.csdnimg.cn/direct/e9e70cb0e1074220b58adab2bd5ff3f3.png)