System V IPC:消息队列
2020-02-26 本文已影响0人
FakeCSer爱去网吧
概念
- 底层是一个链队列
- 与共享内存的不同是:内核要保证消息队列的FIFO性质,因此当有多个接收方进程接收消息队列中的消息的时候,不会产生冲突,由内核来协调他们的执行顺序。由于队列性质,队尾写,队头读,所以读写也不会存在冲突。
API和涉及的数据结构
创建消息队列
#include <sys/msg.h>
int msgget(key_t key,int flag);
参数和返回值类比共享内存shmget
发送消息
#include <sys/msg.h>
int msgsnd(int msqid,void * ptr,size_t nbytes,int flag);
参数表:
msqid:消息队列ID
ptr:指向待发送的消息的指针
nbytes:消息的大小
flag:当消息队列满时如何处理(IPC_NOWAIT?)
返回值:
0:成功
-1:失败
- 消息结构体:
msgsnd结构体中的ptr指向要发送的信息,此信息是一个结构体,需要用户自己定义,但是必须包含消息类型和消息的内容,例如下
struct mymsg
{
long msgtype;
char msgtext[MAXLENTH];
}
接收信息
#include <sys/msg.h>
int msgrcv(int msqid,void * ptr,size_t nbytes,long type,int flag);
参数表:
msqid:消息队列ID
ptr:指向待发送的消息的指针
nbytes:消息的大小
type:消息类型
flag:当消息队列满时如何处理(NOWAIT?)
返回值:
大于0:消息中数据部分的长度
-1:失败
- 消息类型的用法
type = 0时,返回队列中的第一个消息
type > 0时,返回队列中消息类型为type的第一个消息
type < 0时,返回消息队列中类型值小于或等于type的消息,若有多个,则返回最小的
注意数据大小要满足:消息队列定义的消息信息大小>=msgrcv中的数据大小>=msgsnd中的数据大小(即MAXLENTH>=msgrcv中nbytes>=msgsnd中的nbytes
消息队列操作
#include <sys/msg.h>
int msg(int msqid,int cmd,struct msqid_ds * buf);
参数表:
msqid:消息队列ID
cmd:待执行的操作
buf:存放消息队列属性的内存地址
返回值:
0:成功
-1:失败
示例代码
写端:创建消息队列,发送消息
#include <sys/msg.h>
#include <iostream>
#include <unistd.h>
#include <cstring>
#include <sys/ipc.h>
using namespace std;
#define MAXLENTH 128
struct msg_st
{
int msg_type;
char msg_text[MAXLENTH];
};
int main()
{
int msg_id;
int key = ftok(".",512);
char buf[10];
struct msg_st sndMsg;
sndMsg.msg_type = 1;
msg_id = msgget(key,IPC_CREAT|0666);
if(msg_id == -1)
{
perror("msgget");
exit(EXIT_FAILURE);
}
cin >> buf;
strcpy(sndMsg.msg_text,buf);
if(msgsnd(msg_id,(void *)&sndMsg,10,0)==-1)
{
perror("msgsnd");
exit(EXIT_FAILURE);
}
sleep(10);
return 0;
}
读端:接收信息,删除消息队列
#include <sys/msg.h>
#include <iostream>
#include <sys/ipc.h>
#include <cstring>
using namespace std;
#define MAXLENTH 128
struct msg_st
{
int msg_type;
char msg_text[MAXLENTH];
};
int main()
{
int msg_id;
int key = ftok(".",512);
char buf[100];
struct msg_st rcvMsg;
msg_id = msgget(key,0666);
if(msg_id == -1)
{
perror("msgget");
exit(EXIT_FAILURE);
}
if(msgrcv(msg_id,(void *)&rcvMsg,20,0,0)==-1)
{
perror("msgrcv");
exit(EXIT_FAILURE);
}
cout <<rcvMsg.msg_text <<endl;
msgctl(msg_id,IPC_RMID,0);
return 0;
}