消息队列
- 一. 什么是消息队列
- 二. 消息队列有关函数
- 1.获取key - ftok
- 2.创建消息队列 - msgget
- 3.发送消息 - msgsnd
- 4.接收消息 - msgrcv
- 5.删除消息队列 - msgctl
- 三. 实例
- 注意:
一. 什么是消息队列
消息队列独立于发送消息的进程和接收消息的进程,消息队列是消息的链表,存放在内核中并由消息队列标识符标识。
每个消息队列都有一个标识,只有持有这个标识的进程才可以去里面拿消息
生命周期随内核,消息队列会一直存在,需要我们调用接口删除或使用命令删除
二. 消息队列有关函数
1.获取key - ftok
功能 : 获取一个独一无二的key,作为传给共享内存的一个参数
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
key_t key = ftok("./read", 'a');
pathname:
提前创建的可访问文件的文件名,可以随意写
proj_id:
任意一个字符
返回值:
成功则返回生成的key值,失败则返回-1
2.创建消息队列 - msgget
功能 : 创建消息队列
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
int msgget(key_t key,int msgf1g);
key:
ftok得到的key值或者IPC_PRIVATE(创建私有的消息队列)
msgf1g:
IPC_CREAT | 0664
返回值:
成功: 返回消息队列id
失败: 返回-1;
3.发送消息 - 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);
int msgsnd(int msqid,const void *msgp,size_t msgsz,int msgf1g);
smqid:
创建或者打开消息队列得到的id号
msgp:
是一个结构体指针,类型为struct msgbuf *,表示为发送消息结构体的首地址
struct msgbuf {
long mtype; /* message type, must be > 0 */ 类型
char mtext[1]; /* message data */ 数据
};
msgsz:
消息正文内容的大小
msgf1g:
0:阻塞方式发送
IPC_NOWAIT:以非阻塞方式发送
返回值:
成功:0
失败:-1
例如:
typedef struct msgbuf//定义消息结构体
{
1ong mtype;
char mtext[1024];
}MSG;
#define LEN (sizeof(MSG)-sizeof(long)) //计算消息正文内容大小
MSG msg; //定义消息结构体变量
while(1)
{
msg.mtype = 100; //封装消息类型
fgets(msg.mtext,1024,stdin); //输入消息正文
msg.mtext[str1en(msg.mtext)-1] = '\O';
msgsnd(id,&msg,LEN,O); //发送消息
}
4.接收消息 - msgrcv
功能 : 接收数据
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
ssize_t msgrcv(int msgid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
ssize_t msgrcv(int msgid, void *msgp,size_t msgsz,long msgtyp, long msgflg);
msgid:
创建或者打开消息队列得到的id号
msgp:
发送消息结构体的首地址
msgsz:
消息正文的长度 sizeof(msg) - sizeof(long)
msgtyp:
消息的类型
msgflg:
0:阻塞方式发送
IPC_NOWAIT:以非阻塞方式发送
返回值:
成功:0
失败:-1
5.删除消息队列 - msgctl
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
int msgct1(int msgid, int cmd,struct msqid_ds *buf);功能:控制函数
参数:
msgid:
创建或者打开消息队列得到的id号
cmd:
IPC_STAT:获取消息队列信息,将信息存储在第三个参数地址当中
IPC_SET:设置消息队列,将第三个参数的地址的消息队列内容,设置到内核消息队列当中
IPC_RMID:删除消息队列
buf:
如果第二个参数为 IPC_RMID,该值可以为NULL
返回值:
成功: 0
失败: -1
三. 实例
子进程发送消息,父进程接收消息
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
#include <sys/wait.h>
struct msgbuf{
long mtype;
char mtext[50];
};
int main(int argc, char *argv[])
{
//1.获取key
key_t key = ftok("/",'a');
if(key == -1)
{
perror("ftok");
return -1;
}
//2.创建消息队列
int msgid = msgget(key,IPC_CREAT | 0664);
if(msgid == -1)
{
perror("msgget");
return -1;
}
// 进程间通信
pid_t pid = fork();
if(pid < 0)
{
perror("fork");
//如果创建进程失败,删除消息队列
goto xxx;
}
else if(pid == 0)
{
struct msgbuf buf;
while(1)
{
/******发送消息******/
//初始化结构体
buf.mtype = 10;
gets(buf.mtext);
msgsnd(msgid,&buf,sizeof(buf) - sizeof(long),0);
}
}
else
{
struct msgbuf buf;
/******收消息******/
while(1)
{
msgrcv(msgid,&buf,sizeof(buf) - sizeof(long),10,0);
printf("massge: %s\n",buf.mtext);
memset(buf.mtext,0,sizeof(buf.mtext));
}
}
//删除消息队列
int ret = msgctl(msgid, IPC_RMID, NULL);
if(ret == -1)
{
perror("msgctl");
goto xxx;
}
xxx:
sleep(2);
char str[100] = {0};
//使用命令删除消息队列
sprintf(str, "ipcrm -q %d", msgid);
system(str);
system("ipcs -q");
return 0;
}
注意:
ipcs -q: //查询显示当前系统的消息队列
ipcrm -q msgid: //删除某个消息队列