4.消息队列
消息队列,是消息的链表,存放在内核中,一个消息队列由一个标识符(队列ID)来标识。
- 查看消息队列指令
- ipcs -q
- ipcs -q
4.1特点
-
消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级
-
消息队列独立于发送和接收进程,进程终止时,消息队列及其内容仍存在
-
消息队列可以实现消息的随机查询,消息不一定要先进先出的次序读取,也可以按消息的类型读取。
4.2.相关函数
1.int msgget(key_t key, int msgflg);
//创建或打开消息队列,
/*
*参数:
*key:和消息队列关联的key值
*msgflg:是一个权限标志,表示消息队列的访问权限,它与文件的访问权限一样。msgflg可以与IPC_CREAT做或
*操作,表示当key所命名的消息队列不存在时创建一个消息队列,如果key所命名的消息队列存在时,IPC_CREAT标志会被
*忽略,而只返回一个标识符。
*返回值:成功返回队列ID,失败则返回‐1,
*/
2.int msgctl(int msqid, int cmd, struct msqid_ds *buf);
//控制消息队列,成功返回0,失败返回‐1
/*参数:
*msqid:消息队列的队列ID
*cmd:
* IPC_STAT:把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds的值。
* IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值
* IPC_RMID:删除消息队列
*buf:是指向 msgid_ds 结构的指针,它指向消息队列模式和访问权限的结构
*返回值:成功:0,失败:‐1*/
在以下两种情况下,msgget将创建一个新的消息队列:
-
如果没有与键值key相对应的消息队列,并且flag中包含了IPC_CREAT标志
-
key参数为IPC_PRIVATE
创建/删除一个消息队列
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int main()
{
int msgid;
msgid = msgget(IPC_PRIVATE,0755);//创建消息队列
if(msgid == -1)
{
printf("create message queue failed\n");
return -1;
}
printf("create message queue successed! msgid is %d\n",msgid);
system("ipcs -q");//查看消息队列
msgctl(msgid,IPC_RMID,NULL);//删除ID为msgid的消息队列
system("ipcs -q");
return 0;
}
3.int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
//读取消息,成功返回消息数据的长度,失败返回‐1
/*
*@param:
* msgid:消息队列的ID
* msgp:指向消息的指针,常用结构体msgbuf如下:
* struct msgbuf
* {
* long mtype; //消息类型
* char mtext[N]; //消息正文
* }
* size:发送的消息正文你的字节数
* flag:
* IPC_NOWAIT 消息没有发送完成函数也会立即返回
* 0:知道发送完成函数才返回
*@return:成功:0失败:‐1
*/
4.ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
//从一个消息队列中获取消息
/*
*@param:
* msgid:消息队列的ID
* msgp:要接收消息的缓冲区
* size:要接收的消息的字节数
* msgtype:
* 0:接收消息队列中第一个消息
* 大于0:接收消息队列中第一个类型为msgtyp的消息
* 小于0:接收消息队列中类型值不大于msgtyp的绝对值且类型值又最小的消息。
* flag:
* 0:若无消息函数一直阻塞
* IPC_NOWAIT:若没有消息,进程会立即返回ENOMSG。
*@return:成功:接收到的消息i长度,出错:‐1
*/
注意:
消息队列读取之后结点仍存在,但是内容会被清空!
函数msgrcv在读取消息队列时,type参数有下面几种情况
- type ==0,返回队列中的第一消息
- type >0,返回队列中消息队列类型为type的第一个消息 t
- ype <0,返回队列中消息类型值小于或等于type绝对值的消息,如果有多个,则取类型值最小的消息。
可以看出,type值非0时用于以非先进先出次序读取消息,也可以把type看成优先级的权值
创建一个消息队列发送一个hello world 并读取
#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 ID[4];
};
int main()
{
ssize_t ret;
struct msgbuf sndbuf,readbuf;
int msgid;
msgid = msgget(IPC_PRIVATE,0755);//创建消息队列
if(msgid == -1)
{
printf("create message queue failed\n");
return -1;
}
printf("creat message queue successed\n");
//init struct
sndbuf.mtype = 100;//给消息队列赋值类型
printf("please input message:");
fgets(sndbuf.mtext,128,stdin);//从终端读取要发送的信息
msgsnd(msgid,(void *)&sndbuf,strlen(sndbuf.mtext),0);//发送一个队列
system("ipcs -q");
//read
memset(readbuf.mtext,0,128);//初始化读队列的文本内容
ret = msgrcv(msgid,(void *)&readbuf,128,100,0);//读消息队列的内容
printf("total is %ld byte message is %s\n",ret,readbuf.mtext);
system("ipcs -q");
return 0;
}
ftok函数
key_t ftok( char * fname, int id )
//系统建立IPC通讯(如消息队列、共享内存时)必须指定一个ID值。通常情况下,该id值通过ftok函数得到。
/*参数:
*fname就时你指定的文件名(该文件必须是存在而且可以访问的)。
*id是子序号, 虽然为int,但是只有8个比特被使用(0‐255)。
*返回值:当成功执行的时候,一个key_t值将会被返回,否则 ‐1 被返回。
*/
消息队列进程间的通信
//msg_write
#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 ID[4];
};
int main()
{
ssize_t ret;
struct msgbuf sndbuf;
int msgid;
key_t key;
key = ftok("a.c",1);
msgid = msgget(key,IPC_CREAT|0755);
if(msgid == -1)
{
printf("create message queue failed\n");
return -1;
}
printf("creat message queue successed msgid is %d\n",msgid);
//init struct
sndbuf.mtype = 100;
while(1)
{
memset(sndbuf.mtext,0,128);
printf("please input message:");
fgets(sndbuf.mtext,128,stdin);
msgsnd(msgid,(void *)&sndbuf,strlen(sndbuf.mtext),0);
}
return 0;
}
//msg_read
#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 ID[4];
};
int main()
{
ssize_t ret;
struct msgbuf readbuf;
int msgid;
key_t key;
key = ftok("a.c",1);
msgid = msgget(key,IPC_CREAT|0755);
if(msgid == -1)
{
printf("create message queue failed\n");
return -1;
}
printf("creat message queue successed msgid is %d\n",msgid);
//read
while(1)
{
memset(readbuf.mtext,0,128);
ret = msgrcv(msgid,(void *)&readbuf,128,100,0);
printf("message is %s\n total is %ld byte\n",readbuf.mtext,ret);
}
return 0;
}
消息队列全双工通信
全双工双方都可以发送和接收
父子进程分别实现发送和接收的功能(fork创造出的父子进程互相争抢cpu的使用权)
//msg_service
#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 ID[4];
};
int main()
{
ssize_t ret;
struct msgbuf sndbuf,readbuf;
int msgid;
pid_t pid;
key_t key;
key = ftok("a.c",1);
msgid = msgget(key,IPC_CREAT|0755);
if(msgid == -1)
{
printf("create message queue failed\n");
return -1;
}
printf("creat message queue successed msgid is %d\n",msgid);
//init struct
sndbuf.mtype = 100;
//creat child process
pid = fork();
if(pid > 0)//write 100 message
{
while(1)
{
memset(sndbuf.mtext,0,128);
printf("please input message:");
fgets(sndbuf.mtext,128,stdin);
msgsnd(msgid,(void *)&sndbuf,strlen(sndbuf.mtext),0);
}
}
else if(pid == 0)//read 200 message
{
while(1)
{
memset(readbuf.mtext,0,128);
ret = msgrcv(msgid,(void *)&readbuf,128,200,0);
printf("type 200 :%s\n",readbuf.mtext);
}
}
return 0;
}
//msg_client
#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 ID[4];
};
int main()
{
ssize_t ret;
struct msgbuf sndbuf,readbuf;
int msgid;
pid_t pid;
key_t key;
key = ftok("a.c",1);
msgid = msgget(key,IPC_CREAT|0755);
if(msgid == -1)
{
printf("create message queue failed\n");
return -1;
}
printf("creat message queue successed msgid is %d\n",msgid);
//init struct
sndbuf.mtype = 200;
//creat child process
pid = fork();
if(pid > 0)//write 200 message
{
while(1)
{
memset(sndbuf.mtext,0,128);
printf("please input message:");
fgets(sndbuf.mtext,128,stdin);
msgsnd(msgid,(void *)&sndbuf,strlen(sndbuf.mtext),0);
}
}
else if(pid == 0)//read 100 message
{
while(1)
{
memset(readbuf.mtext,0,128);
ret = msgrcv(msgid,(void *)&readbuf,128,100,0);
printf("type 100 :%s\n",readbuf.mtext);
}
}
return 0;
}