消息队列是进程间通信的一种方法,他有两个操作,一个进程来发送消息(也就是向内存中写入数据),另一个是获取消息(也就是另外一个进程在内存中读取数据)
下面来看消息队列的
创建,写入,读取等需要用到的函数
创建:msgget((key_t) key,int msgflg) 其中(key_t)key的话,我在管道,共享内存中都写过,key值没什么要求,大于零的32位整数就行,并且它是用来区分和别的消息队列的,所以key值别和其他消息队列重复就行
msgflg是个标志位,一般取IPC_CREAT :
如果消息队列对象不存在,则创建之,否则则进行打开操作;下面附上帮助手册
写入数据(发送消息):int msgsnd ( int msqid, struct msgbuf *msgp, int msgsz, int msgflg )
其中参数msqid就是上述创建的消息队列的id
struct msgbuf *msgp这玩意就是结构体指针 该结构体就是消息体
msgsz就是消息体的大小
msgflg一般默认为0
读取数据(读取消息):size_t msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz, long type,int msgflg)
smqid就是创建的消息队列id
struct msgbuf *msgp 结构体指针
size_t msgsz 就是存消息的大小
long type 就是消息的类型
int msgflg标志位,一般默认0
下面附上帮助手册:
上述那个结构体struct msgbuf就是消息体,type用来区分消息,你发送或者获取消息的类型,其类型必须是long
下面的char 的数组就是发送或者获取消息的最大内存(这里有一点要提一下,就是上面说到msgsnd中消息体大小,只算这个结构体中的char数组,龙不计算在内)
下面来进行代码实现:发送端的编写
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/msg.h>
struct message
{
long type;
char buff[32];
};
int main()
{
int msgid = msgget((key_t)1234,IPC_CREAT|0600);//0600是权限
assert(msgid != -1);
struct message me;
me.type = 1; //这块将消息类型定义为1
strcpy(me.buff,"hello"); //向buff中写入hello
msgsnd(msgid,(void*)&me,32,0); //向消息队列发送消息
}
对获取端的编写:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/msg.h>
struct message
{
long type;
char buff[32];
};
int main()
{
int msgid = msgget((key_t)1234,IPC_CREAT|0600);//0600是权限
assert(msgid != -1);
struct message me;
msgrcv(msgid,&me,32,1,0); //消息存储最多32 1是type类型 0是默认标志位
printf("read msg:%s \n",me.buff);
}
下面附上运行截图(其中xiaoxi是发送消息,haha是获取消息) 那个已用字节数应该是32 因为xiaoxi这个发送端 我刚刚运行了下 ,所以叠加起来就是64
然后ipcs -q是查看消息队列的使用情况的,键下面的4d2就是1234转换为16进制的值
然后我们将发送消息的消息的类型值由1改为2,获取端代码不变,我们再来看一下结果
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/msg.h>
struct message
{
long type;
char buff[32];
};
int main()
{
int msgid = msgget((key_t)1234,IPC_CREAT|0600);//0600是权限
assert(msgid != -1);
struct message me;
me.type = 2; //这块将消息类型定义为1
strcpy(me.buff,"hello"); //向buff中写入hello
msgsnd(msgid,(void*)&me,32,0); //向消息队列发送消息
}
然后我们就会发现,获取端获取不了数据,一直在那块阻塞,因为类型不对,写入端写的是2类型,读取的是1类型
因为类型不对,写入端写的是2类型,读取的是1类型,所以肯定是读取不了的,那么有没有什么办法让它可以读取呢,最笨的办法就是将读取端的消息类型改为2,这也是最常规的办法,下面我来弄一个很有意思的方法:
将读取端msgrcv的消息类型改为0,也就是默认类型,这样的话,它就会接受所有的数据类型,下面我们来试一下:只改获取端,发送端代码不该,还是2类型
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/msg.h>
struct message
{
long type;
char buff[32];
};
int main()
{
int msgid = msgget((key_t)1234,IPC_CREAT|0600);//0600是权限
assert(msgid != -1);
struct message me;
msgrcv(msgid,&me,32,0,0); //消息存储最多32 1是type类型 0是默认标志位
printf("read msg:%s \n",me.buff);
}
附上运行截图:
然后删除消息队列msgctl(msgid,IPC_RMID,NULL)
将该代码写到获取端的末尾就好!
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/msg.h>
struct message
{
long type;
char buff[32];
};
int main()
{
int msgid = msgget((key_t)1234,IPC_CREAT|0600);//0600是权限
assert(msgid != -1);
struct message me;
msgrcv(msgid,&me,32,0,0); //消息存储最多32 1是type类型 0是默认标志位
printf("read msg:%s \n",me.buff);
if(msgctl(msgid,IPC_RMID,NULL) == -1) //这块msgctl中的那个NULL参数还没搞明白 下次课过去问一下老师在评论区补一下
{
printf("delete error");
}
}
这样执行下来就可以在程序执行完成之后,删除消息队列!
“加油呀 兄弟们 BAT 我来了”