消息队列特性
- 消息队列存在于Linux内核中,可以使数据双向流动
- 数据在内核中,即使进程结束数据依然存在
- 消息队列实际上是消息链表,每个队列都有自己的标识符
消息队列API
- msgget——创建一个消息队列
- msgsnd、msgrcv——添加数据到消息队列、从消息队列获取数据
- msgctl——控制消息队列
一、msgget——创建一个消息队列
1.原函数
表头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
定义函数
int msgget(key_t key, int msgflg);
函数说明——创建和访问一个消息队列
key——消息队列的名称(使用ftok()函数获取)
msgflg——消息队列的访问权限
返回值——成功返回此消息队列的标识符(非零整数)。失败时返回-1,失败原因在errno中
2.示例
key_t key;
key = ftok(".",'z');
int msgId = msgget(key,IPC_CREAT|0777);//创建和访问一个消息队列
二、msgsnd、msgrcv——添加数据到消息队列、从消息队列获取数据
1.原函数
表头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
定义函数
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
函数说明——msgsnd()添加数据到消息队列、msgrcv()从消息队列获取数据
msqid —— 由msgget()返回的队列标识符
msgp —— 需要存放/读取的结构体
msgsz —— 需要存放/读取的大小
msgtyp —— 读取消息队列的位置
msgflg —— 默认值为0
返回值——成功msgsnd()返回0,msgrcv()返回实际复制到mtext数组中的字节数。错误两个函数都返回-1,errno表示错误
2.参数取值
msgp默认结构体如下:
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
3.示例
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
struct msgbuf sendBuf = {988,"thank your welcome\n"};
struct msgbuf readBuf;
msgrcv(msgId,&readBuf,sizeof(readBuf.mtext),888,0);//从消息队列获取数据
msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);//添加数据到消息队列
三、msgctl——控制消息队列
1.原函数
表头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
定义函数
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
函数说明—— 控制消息队列,它与共享内存的shmctl函数相似
msqid —— 由msgget()返回的队列标识符
cmd —— 控制msqid_ds结构体指令
buf —— 记录消息队列的信息(消息队列模式和访问权限)(默认为NULL)
返回值——成功时返回0。失败时返回-1,errno表示错误
2.参数取值
command是将要采取的动作,它可以取3个值,
IPC_STAT:把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds的值。
IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值
IPC_RMID:删除消息队列
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) */
};
3.示例
消息队列通信例程
程序1
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[50]; /* message data */
};
int main()
{
struct msgbuf sndbuf={889,"Hello"};
struct msgbuf rcvbuf;
key_t key;
int msgid;
key=ftok(".",'k');//键值获取
msgid=msgget(key,IPC_CREAT|0777);//创建一个消息队列
msgsnd(msgid,&sndbuf,sizeof(sndbuf.mtext),0);//添加数据到消息队列
msgrcv(msgid,&rcvbuf,sizeof(rcvbuf.mtext),888,0);//从消息队列获取数据
printf("rcvbuf.mtype=%ld,rcvbuf.mtext=%s\n",rcvbuf.mtype,rcvbuf.mtext);
msgctl(msgid,IPC_RMID,NULL);//删除消息队列
return 0;
}
程序2
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[50]; /* message data */
};
int main()
{
struct msgbuf sndbuf={888,"World"};
struct msgbuf rcvbuf;
key_t key;
int msgid;
key=ftok(".",'k');//键值获取
msgid=msgget(key,IPC_CREAT|0777);//访问一个消息队列
msgrcv(msgid,&rcvbuf,sizeof(rcvbuf.mtext),889,0);//从消息队列获取数据
printf("rcvbuf.mtype=%ld,rcvbuf.mtext=%s\n",rcvbuf.mtype,rcvbuf.mtext);
msgsnd(msgid,&sndbuf,sizeof(sndbuf.mtext),0);//添加数据到消息队列
msgctl(msgid,IPC_RMID,NULL);//删除消息队列
return 0;
}
运行结果:打开任意程序后消息队列阻塞,等待另外一个程序将所需数据录入,开启另外一程序后两程序达到消息通信的目的。
rcvbuf.mtype=889,rcvbuf.mtext=Hello
rcvbuf.mtype=888,rcvbuf.mtext=World
星辰~念