简介
消息队列是消息的链接表 ,存放在内核中并由消息队列标识符标识。我们将称消息队列为“队列”,其标识符为“队列id”。对消息队列有写权限的进程可以按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读出消息。Linux采用消息队列的方式来实现消息传递。这种消息的发送方式是:发送方不必等待接收方检查它所收到的消息就可以继续工作下去,而接收方如果没有收到消息也不需等待。
Linux用宏MSGMAX和MSGMNB来限制一条消息的最大长度和一个队列的最大长度。
ftok函数
通过ftok函数得到id值
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
系统建立IPC通讯(如消息队列、共享内存时)必须指定一个ID值。通常情况下,该id值通过ftok函数得到。
参数:pathname:文件名(含路径)
参数projid:项目ID,必须为非0整数(0-255)
msgget函数
用来创建新的消息队列或获取已有的消息队列。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
返回值: 调用成功:消息队列的标识符;调用失败: -1.
参数key: 消息队列对象的关键字(key),函数将它与已有的消息队列对象的关键字进行比较来判断消息队列对象是否已经创建。
参数msgflg:msgflg 控制函数具体操作。它可以取下面的几个值:
IPC_CREAT :如果消息队列对象不存在,则创建之,否则则进行打开操作;
IPC_EXCL: 和IPC_CREAT 一起使用(用”|”连接),如果消息对象不存在则创建之,否则产生一个错误并返回-1。
msgsnd函数
进程利用它来向消息队列发送消息。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数msqid: 是消息队列对象的标识符(由msgget()函数得到)
参数msgp : 指向要发送的消息所在的内存,
参数msgsz: 是要发送信息的长度(字节数),可以用公式计算。(msgsz = sizeof(struct mymsgbuf) - sizeof(long);)
参数msgflg:是控制函数行为的标志,可以取以下的值:
0:忽略标志位
IPC_NOWAIT:如果消息队列已满,消息将不被写入队列,控制权返回调用函数的线程。如果不指定这个参数,线程将被阻塞直到消息被可以被写入。
msgrcv函数
从标识符为msgid的消息队列里接收一个指定类型的消息并存储于msgp中读取后把消息从消息队列中删除
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
返回值: 调用成功:从消息队列里拷贝过来的字节数;调用失败:返回-1;
函数的前三个参数和msgsnd()函数中对应的参数的含义是相同的。
第四个参数mtype:
指定了函数从队列中所取的消息的类型。函数将从队列中搜索类型与之匹配的消息并将之返回。如果mtype 的值是零的话,函数将不做类型检查而自动返回队列中的最旧(优先级最小的)的消息。
第五个参数依然是是控制函数行为的标志,取值可以是:
0:表示忽略;
MSG_NOERROR:如果函数取得的消息长度大于msgsz,将只返回msgsz 长度的信息,
剩下的部分被丢弃了。如果不指定这个参数,E2BIG 将被返回,而消息则留在队列中不被
取出。
IPC_NOWAIT:如果消息队列为空,则返回一个ENOMSG,并将控制权交回调用函数
的进程。如果不指定这个参数,那么进程将被阻塞直到函数可以从队列中得到符合条件的
消息为止。如果一个client 正在等待消息的时候队列被删除,EIDRM 就会被返回。如果进
程在阻塞等待过程中收到了系统的中断信号,EINTR 就会被返回。
msgctl函数
直接控制消息队列的行为
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
返回值:调用成功就返回0;失败就返回-1
参数msgqid :是消息队列对象的标识符。
参数cmd是函数要对消息队列进行的操作,它可以是:
IPC_STAT:取出系统保存的消息队列的msqid_ds 数据,并将其存入参数buf 指向的msqid_ds 结构中
IPC_SET:设定消息队列的msqid_ds 数据中的msg_perm 成员。设定的值由buf 指向的msqid_ds结构给出。
IPC_EMID:将队列从系统内核中删除。
代码实现
msgget.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[256]; /* message data */
};
int main()
{
struct msgbuf readBuf;
key_t key;
key = ftok(".",'m');
printf("key=%x\n",key);
int msgId = msgget(key, IPC_CREAT|0777);
if(msgId == -1 ){
printf("get que failuer\n");
}
memset(&readBuf,0,sizeof(struct msgbuf));
msgrcv(msgId, &readBuf,sizeof(readBuf.mtext),888,0);//接收
printf("read from que:%s\n",readBuf.mtext);
struct msgbuf sendBuf = {988,"thank you for reach"};
msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);//写入
msgctl(msgId,IPC_RMID,NULL);//删除消息队列对象
return 0;
}
msgsend.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[256]; /* message data */
};
int main()
{
struct msgbuf sendBuf = {888,"this is message from quen"};
struct msgbuf readBuf;
memset(&readBuf,0,sizeof(struct msgbuf));
key_t key;
key = ftok(".",'m');
printf("key=%x\n",key);
int msgId = msgget(key, IPC_CREAT|0777);
if(msgId == -1 ){
printf("get que failuer\n");
}
msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);//写入
printf("send over\n");
msgrcv(msgId, &readBuf,sizeof(readBuf.mtext),988,0);//接收
printf("reaturn from get:%s\n",readBuf.mtext);
msgctl(msgId,IPC_RMID,NULL);
return 0;
}
编译运行