一、 基本原理
消息队列本质就是内核中的一条内部链表(内核链表),并且每个消息队列都有自己唯一的标识符。标识符是通过键值创建出来的,如果不同的进程,根据同一个键值可以获取同一个消息队列,从而实现进程间的通讯。消息队列中的消息可以设置类型的。读取消息也可以根据类型读取, 默认读取第一个消息。如果指定类型,会从队头找到第一个指定类型的消息读取。
二、消息队列的常用函数
1. 创建消息队列
int msgget(key_t key, int msgflg);
功能描述:
如果键值对应的消息队列存在,返回消息队列的标识符。
如果键值对应的消息队列不存在, 根据第二个参数的权限去创建
参数:
key: 关键字
msgflg: 标志 IPC_CREAT|0777
返回值:
成功返回消息队列的标识符,失败返回-1
int main(){
int semid;
semid = semget(0x500,1,IPC_CREAT | 0777);
if(semid < 0){
perror("semget");
return -1;
}
printf("semget ok...\n");
return 0;
}
2. 发送消息
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能描述:
往消息队列中发送消息
参数:
msqid: 消息队列的标识符
msgp: 传入参数,打包消息基本信息结构体变量的起始地址
msgsz: 消息内容的大小
msgflg: 设置阻塞标志, 0表示阻塞
返回值:
成功返回0,失败返回-1
打包消息的结构体要按照以下格式定义:
struct msgbuf {
long mtype; /*消息的类型*/
char mtext[1]; /* 消息的内容 */
};
#include <stdio.h>
#include <sys/msg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
struct msgbuf{
long mtype;
char mtext[1024];
};
int main(){
int msgid,ret;
msgid = msgget(0x200,IPC_CREAT | 0777);
if(msgid < 0){
perror("msget");
return -1;
}
struct msgbuf mb1 = {1,"hi"};
struct msgbuf mb2 = {3,"wanghan"};
ret = msgsnd(msgid,&mb1,strlen(mb1.mtext),0);
if(ret < 0){
perror("msgsnd");
return -1;
}
ret = msgsnd(msgid,&mb2,strlen(mb2.mtext),0);
if(ret < 0){
perror("msgsnd");
return -1;
}
printf("send ok\n");
return 0;
}
3. 接受消息
size_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
功能描述:
从消息队列中读取消息
参数:
msqid:消息队列的标识符
msgp: 传出参数,返回消息的基本信息,需要传一个接收消息基本信息变量的地址过来
msgsz: 消息内容的大小
msgtpe: 指定消息的类型
0:默认读取第一个消息
>0:从队头开始找到第一个指定的消息读取
msgflg: 设置阻塞标志, 0表示阻塞
返回值:成功返回实际读到的字节数,失败返回-1
#include <stdio.h>
#include <sys/msg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
struct msgbuf{
long mtype;
char mtext[1024];
};
int main(){
int msgid,ret;
msgid = msgget(0x200,IPC_CREAT | 0777);
if(msgid < 0){
perror("msget");
return -1;
}
struct msgbuf mb1;
struct msgbuf mb2;
ret = msgrcv(msgid,&mb1,1024,1,0);
if(ret < 0){
perror("msgrcv");
return -1;
}
ret = msgrcv(msgid,&mb2,1024,3,0);
if(ret < 0){
perror("msgrcv");
return -1;
}
printf("%ld,msg1:%s,%ld,msg2:%s\n",mb1.mtype,mb1.mtext,mb2.mtype,mb2.mtext);
return 0;
}
4. 删除消息队列
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参数:
msqid: 消息队列的标识符
cmd: 命令(IPC_RMID 删除消息队列)
buf: 如果是删除操作,第三个参数忽略
返回值:
成功返回0, 失败返回-1
semctl(semid,0,SETVAL,1); // init
三、其他
ipcs: 查看系统进程通讯方式的基本信息
Ipcrm : 删除某个通讯方式
Ipcrm -Q 键值
Ipcrm -q 标识符