消息队列,是消息的链接表,存放在内核中,是在消息的传输过程中保存消息的容器。。一个消息队列由一个标识符(即队列ID)来标识。
消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。
看个图
在这里不用去管Linux内核如何去操作,我们需要关心在一次收发消息中,A或者B如何发送消息的,同时又是如何接收消息的。每一次过程都是通过指定的或者说相同的id去找到相应的结构体的mtext消息进行read或者write
#include
#include
#include
// 创建或打开消息队列:成功返回队列ID,失败返回-1
int msgget(key_t key, int flag);
// 添加消息:成功返回0,失败返回-1
int msgsnd(int msqid, const void *ptr, size_t size, int flag)
// 读取消息:成功返回消息数据的长度,失败返回-1
int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);
// 控制消息队列:成功返回0,失败返回-1
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
int msgget(key_t key, int flag);
功能:
创建或打开消息队列。
在以下两种情况下,msgget将创建一个新的消息队列。
参数:
key:消息队列的id值
msgflg:是一个权限标志,表示消息队列的访问权限,它与文件的访问权限一样。msgflg可以与IPC_CREAT做或操作(IPC_CREAT|0777,后面加上文件执行权限),表示当key所命名的消息队列不存在时创建一个消息队列,如果key所命名的消息队列存在时,IPC_CREAT标志会被忽略,而只返回一个标识符。
返回值:
成功返回队列id,失败则返回‐1,
int msgsnd(int msqid, const void *ptr, size_t size, int flag)
功能:
读取消息,成功返回消息数据的长度,失败返回‐1
参数:
msgid:消息队列的ID
msgp:指向消息信息的指针,man手册中给出的结构体msgbuf如下:
struct msgbuf
{
long mtype; //消息类型
char mtext[1]; //消息正文
};
size:消息的字节数
flag:
IPC_NOWAIT 消息没有发送完成,函数也会立即返回
0 知道发送完成,函数才返回
注意:
这个别写错了。。。。。我就容易写成msgsend
int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);
功能:
获取消息队列的消息
参数:
msgid:消息队列的ID
msgp:要接收消息的缓冲区
size:要接收的消息的字节数
msgtype:
type == 0,返回队列中的第一个消息;
type > 0,返回队列中消息类型为 type 的第一个消息;
type < 0,返回队列中消息类型值小于或等于 type 绝对值的消息,如果有多个,则取类型值最小的消息。
flag:
0:若无消息函数一直阻塞
IPC_NOWAIT:若没有消息,进程会立即返回ENOMSG。
返回值:
成功:接收到的消息i长度
出错:‐1
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
功能:
控制消息队列,成功返回0,失败返回‐1
参数:
msqid:消息队列的队列ID
cmd:
IPC_RMID:删除消息队列
buf:NULL吧
!
!
!
!
再补充下ftok函数,等会demo用得到
NAME
ftok - convert a pathname and a project identifier to a System
V IPC key
SYNOPSIS
#include
#include //头文件
key_t ftok(const char *pathname, int proj_id);
以下是百度:
系统建立IPC通讯 (消息队列、信号量和共享内存) 时必须指定一个ID值。通常情况下,该id值通过ftok函数得到。
函数原型:
key_t ftok( const char * fname, int id )
fname就是你指定的文件名(已经存在的文件名),一般使用当前目录,如:
key_t key;
key = ftok(“.”, 1); 这样就是将fname设为当前目录。
id是子序号。虽然是int类型,但是只使用8bits(1-255)。
在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值。
如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。
查询文件索引节点号的方法是: ls -i
当删除重建文件后,索引节点号由操作系统根据当时文件系统的使用情况分配,因此与原来不同,所以得到的索引节点号也不同。
我们上个图看看好理解不?
一个点代表本机目录,两个代表上级目录,前面的是索引节点号, key = ftok(“.”,7);比如我们这样写就是本机目录和数字7他们变换的16进制。同样的 key = ftok(“.”,‘o’);字符也是可以的。
ftok函数
当成功执行的时候,一个key_t值将会被返回,否则 ‐1 被返回。
接下来看看这个demo实例
这是msgget.c文件
#include
#include
#include
#include
#include
#include
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[256]; /* message data */
};
int main(){
int msgid;
key_t key;
struct msgbuf getbuf;
struct msgbuf sendbuf = {988,"hello,i am msgget"};
// key_t ftok(const char *pathname, int proj_id);
key = ftok(".",'o');
printf("key = %x\n",key);
// int msgget(key_t key, int msgflg);
msgid = msgget(key,IPC_CREAT|0777);
if(msgid == -1){
printf("create queue failed!\n");
exit(1);
}
// ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
msgrcv(msgid,&getbuf,sizeof(getbuf.mtext),888,0);
printf("Received send message:%s\n",getbuf.mtext);
// int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
msgsnd(msgid,&sendbuf,sizeof(sendbuf.mtext),0);
// int msgctl(int msqid, int cmd, struct msqid_ds *buf);
msgctl(msgid,IPC_RMID,NULL);
return 0;
}
这是msgsend.c文件
#include
#include
#include
#include
#include
#include
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[256]; /* message data */
};
int main(){
int msgid;
key_t key;
struct msgbuf getbuf = {888,"hello,i am msgsend"};
struct msgbuf sendbuf;
// key_t ftok(const char *pathname, int proj_id);
key = ftok(".",'o');
printf("key = %x\n",key);
// int msgget(key_t key, int msgflg);
msgid = msgget(key,IPC_CREAT|0777);
if(msgid == -1){
printf("create queue failed!\n");
exit(1);
}
// ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
msgsnd(msgid,&getbuf,sizeof(getbuf.mtext),0);
// int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
msgrcv(msgid,&sendbuf,sizeof(sendbuf.mtext),988,0);
printf("Received get message:%s\n",sendbuf.mtext);
// int msgctl(int msqid, int cmd, struct msqid_ds *buf);
msgctl(msgid,IPC_RMID,NULL);
return 0;
}
结果如下:
ending!!!!