3.2 消息队列
有一个队列,队列中存放各种消息。每个进程都可以把数据封存在消息中,再放入队列。
每个进程都可以拿到消息队列,再从中取出/放入消息。
消息队列不会产生覆盖问题,但需要考虑队列长度。
消息队列的编程步骤:
1 生成key,使用ftok()或用头文件定义
2 创建/获取消息队列 msgget()
3 发送/接收消息 msgsnd() / msgrcv()
4 如果不会再被使用(所有进程都不用)可以删除
msgctl()
相关函数:
msgget()用法和shmget()基本一样。获取时flag为0,新建时flag为 权限|IPC_CREAT|IPC_EXCL
msgctl()用法和shmctl()基本一样。
int msgsnd(int msgid,void* p,size_t size,int flag)
msgid 就是消息队列,p是发送的消息的首地址,size是发送消息的大小,flag为0代表阻塞,为IPC_NOWAIT代表非阻塞。(消息满了以后是否等待)
成功返回0,失败返回-1
ssize_t msgrcv(int msgid,void* buf,size_t size,int msgtype,int flag)
msgid、flag和msgsnd()一样
buf是用来接收消息的首地址
size是sizeof(buf)
msgtype 代表消息的类型,消息分为:
无类型消息和有类型消息。
3.2.1 无类型消息
msga.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int main(){
key_t key = ftok(".",100);
if(key==-1) perror("ftok"),exit(-1);
int msgid = msgget(key,
0666|IPC_CREAT|IPC_EXCL);
if(msgid==-1) perror("msgget"),exit(-1);
int res = msgsnd(msgid,"hello",5,0);
if(res==-1) perror("msgsnd"),exit(-1);
printf("send ok\n");
}//练习:写msgb.c,从消息队列中取出hello并打印
----------------------------------------------------------
msgb.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int main(){
key_t key = ftok(".",100);
if(key==-1) perror("ftok"),exit(-1);
int msgid = msgget(key,0);
if(msgid==-1) perror("msgget"),exit(-1);
char buf[100] = {};
int res = msgrcv(msgid,buf,sizeof(buf),0,0);
if(res==-1) perror("msgrcv"),exit(-1);
printf("buf=%s,rcv=%d\n",buf,res);
}
无类型消息可以是任意类型,比如:整数、字符串、浮点…
无类型消息的取出遵循队列的基本准则: FIFO。
3.2.2 有类型消息
有类型消息,类型必须是一个结构体:
struct 自定义名字{
long mtype;//消息类型,必须有,格式固定
char msg[];//数据
};
数据是:char数组,长度和名称可以自定义,用其他类型也可以
mtype取值时,必须 大于0。(赋值时不能<=0)
接收数据时可以按消息类型接收,msgrcv()中的第四个参数可以指定接收消息的类型:
= 0 代表接收任意类型的消息(遵循先入先出)
大于 0 代表接收特定类型的消息(mtype=值)
<0 代表接收类型小于等于参数绝对值的消息
次序从小到大,如果类型相同,按在队列中的位置
有类型消息在计算发送和接收的size时,可以不计算类型所占的空间。(sizeof(struct)-4)。发送和接收要么都计算,要么都不计算。
msgtypea.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
struct mymsg{
long mtype; //类型
char buf[256];// 数据
};
int main(){
key_t key = ftok(".",100);
int msgid = msgget(key,0666|IPC_CREAT);
if(msgid==-1) perror("msgget"),exit(-1);
struct mymsg msg1 = {1,"hello1"};
struct mymsg msg2 = {2,"hello2"};
int res1 = msgsnd(msgid,&msg1,
sizeof(msg1)-4,0);
int res2 = msgsnd(msgid,&msg2,
sizeof(msg2)-4,0);
if((res1==0)&&(res2==0))printf("send ok\n");
}
----------------------------------------------------------
msgtypeb.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
struct mymsg{
long mtype; //类型
char buf[256];// 数据
};
int main(){
key_t key = ftok(".",100);
int msgid = msgget(key,0);
if(msgid==-1) perror("msgget"),exit(-1);
struct mymsg msg;
int res = msgrcv(msgid,&msg,sizeof(msg)-4,
-2,0);
if(res==-1) perror("msgrcv"),exit(-1);
printf("mtype=%ld,msg=%s\n",msg.mtype,
msg.buf);
}