#简介
消息队列就是一些消息的列表,或者说是一些消息组成的队列。消息队列与管道有些类似,消息队列可以认为是管道的改进版。相较于管道的先进先出准则,消息队列在读取时可以按照消息的类型进行读取,这也是消息队列的特点,它可以实现消息随机查询。消息发送时,需要将消息封装,然后添加到队列的末尾即可,而消息接收时则可以根据需求进行选择的读取(读取即将封装的消息从队列中移除)
#函数说明
/*************************************************************
函 数 名 : ftok
功能描述 : 生成IPC KEY
输入参数 : const char *pathname 存在的文件或文件夹
int proj_id 项目代号
pathname和proj_id对应一个IPC KEY
返 回 值 : key_t -1 失败 其它 IPC KEY(用于msgget(2), semget(2), or shmget(2))
*************************************************************/
key_t ftok(const char *pathname, int proj_id);
/*************************************************************
函 数 名 : msgget
功能描述 : 根据key标识生成消息队列,key可以为ftok得到,也可以自定义整数
输入参数 : key_t key ICP KEY或自定义整数
int msgflg
IPC_CREAT | 权限 (IPC_CREAT | 0777)
IPC_CREAT | IPC_EXCL | 权限 (IPC_EXCL 消息队列已存在返回-1)
返 回 值 : int 消息队列ID -1 失败 并设置错误码
int msgget(key_t key, int msgflg);
*************************************************************/
/*************************************************************
struct msgbuf {
long mtype; /消息类型,必须大于0/
char mtext[1]; /发送的数据,柔性数组,可为数组或结构体/
};
函 数 名 : msgsnd
功能描述 : 发送数据到消息队列
输入参数 : int msqid 消息队列标识
const void *msgp 待发送数据
size_t msgsz 待发送数据长度,**不包括消息类型**
int msgflg 0 阻塞模式 **如果待写入的数据量超过当前所剩大小,则阻塞等待直到可写**
IPC_NOWAIT 非阻塞模式 写失败返回失败
返 回 值 : int -1 失败 0 成功
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
*************************************************************/
函 数 名 : msgrcv
功能描述 : 接收消息队列数据
输入参数 : int msqid 消息队列标识
void *msgp 接收数据缓存
size_t msgsz **接收数据缓存大小(必须大于等于发送的数据,否则会读取失败)**
long msgtyp 待接收数据类型
int msgflg 0 **阻塞 直到有数据**
IPC_NOWAIT 非阻塞模式 读失败返回失败
返 回 值 : int -1 失败 >=0 读取的字节数
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
*************************************************************/
/*************************************************************
struct msqid_ds {
struct ipc_perm msg_perm; /* Ownership and permissions */
time_t msg_stime; /* Time of last msgsnd(2) */
time_t msg_rtime; /* Time of last msgrcv(2) */
time_t msg_ctime; /* Time of last change */
unsigned long __msg_cbytes; /* Current number of bytes in
queue (nonstandard) */
msgqnum_t msg_qnum; /* Current number of messages
in queue */
msglen_t msg_qbytes; /* Maximum number of bytes
allowed in queue */
pid_t msg_lspid; /* PID of last msgsnd(2) */
pid_t msg_lrpid; /* PID of last msgrcv(2) */
};
The ipc_perm structure is defined as follows (the highlighted fields are settable using IPC_SET):
struct ipc_perm {
key_t __key; /* Key supplied to msgget(2) */
uid_t uid; /* Effective UID of owner */
gid_t gid; /* Effective GID of owner */
uid_t cuid; /* Effective UID of creator */
gid_t cgid; /* Effective GID of creator */
unsigned short mode; /* Permissions */
unsigned short __seq; /* Sequence number */
};
函 数 名 : msgctl
功能描述 : 消息队列属性操作
输入参数 : int msqid 消息队列标识符
int cmd 操作指令
struct msqid_ds *buf 属性
返 回 值 : int -1 失败 并设置错误码 0 成功
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
*************************************************************/
cmd 包括:IPC_STAT 查看属性
IPC_SET 设置属性
IPC_RMID 删除消息队列
其中IPC_SET可修改的属性有msg_qbytes(容量)msg_perm.uid, msg_perm.gid, msg_perm.mode 并刷新msg_ctime
消息队列属性查看:
ipcs -q 查看当前消息队列状态
1.msgctl 函数的IPC_STAT选项
2.通过指令查看
cat /proc/sys/kernel/msgmnb 消息队列容量
cat /proc/sys/kernel/msgmni 消息队列的最大数量
cat /proc/sys/kernel/msgmax 单条消息的最大字节数
#msgctl实例代码
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
//MSG_PATH和MSG_PROJ_ID 共同索引一个消息队列
#define MSG_PATH "./" //存在的文件夹或文件
#define MSG_PROJ_ID 520 //项目代号 非0整数
#define MSG_TYPE 520 //消息类型
int main(int argc, char *argv[])
{
int ret = -1;
key_t key;
int msg_id;
struct msqid_ds ds_info;
key = ftok(MSG_PATH, MSG_PROJ_ID);
if (-1 == key) //-1失败 并设置错误码 0成功
{
printf("ftok fail errno:%d, %s\n", errno, strerror(errno));
return -1;
}
printf("ftok key:%d\n", key);
msg_id = msgget(key, IPC_CREAT | 0777);
if (-1 == key) //-1失败 并设置错误码 >0的整数
{
printf("msgget fail errno:%d, %s\n", errno, strerror(errno));
return -1;
}
printf("msg_id:%d\n", msg_id);
//查看消息队列属性
msgctl(msg_id, IPC_STAT, &ds_info);
printf("最后一次发送的时间:%ld, 最后一次接收的时间:%ld, 最后一次更新的时间:%ld,当前队列的数据大小:%ld, 当前队列的消息数量:%ld,队列总容量:%ld,最后一次发送的进程id:%d,最后一次接收的进程id:%d\r\n",
ds_info.msg_stime, ds_info.msg_rtime, ds_info.msg_ctime,
ds_info.__msg_cbytes, ds_info.msg_qnum, ds_info.msg_qbytes,
ds_info.msg_lspid, ds_info.msg_lrpid);
//删除消息队列
msgctl(msg_id, IPC_RMID, NULL);
return 0;
}
发送端实例代码:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
//MSG_PATH和MSG_PROJ_ID 共同索引一个消息队列
#define MSG_PATH "./" //存在的文件夹或文件
#define MSG_PROJ_ID 520 //项目代号 非0整数
#define MSG_TYPE 520 //消息类型
#define MSG_ONE_PACKET_LEN 8*1024
typedef struct
{
char buf[MSG_ONE_PACKET_LEN];
}MsgPrivateData_t;
typedef struct
{
long mtype; //消息类型
MsgPrivateData_t private; //自定义数据
}MsgData_t;
int main(int argc, char *argv[])
{
int ret = -1;
key_t key;
int msg_id;
MsgData_t data;
struct msqid_ds info;
memset(&data, 0, sizeof(data));
key = ftok(MSG_PATH, MSG_PROJ_ID);
if (-1 == key) //-1失败 并设置错误码 0成功
{
printf("ftok fail errno:%d, %s\n", errno, strerror(errno));
return -1;
}
printf("ftok key:%d\n", key);
data.mtype = MSG_TYPE;
strncpy(data.private.buf, "msg send", strlen("msg send"));
msg_id = msgget(key, IPC_CREAT | 0777);
if (-1 == key) //-1失败 并设置错误码 >0的整数
{
printf("msgget fail errno:%d, %s\n", errno, strerror(errno));
return -1;
}
printf("msg_id:%d\n", msg_id);
ret = msgsnd(msg_id, (void *)&data, sizeof(data.private), 0); //长度为不包含消息类型的自定义数据
printf("msgsnd ret:%d\n", ret);
return 0;
}
#接收端实例代码
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
//MSG_PATH和MSG_PROJ_ID 共同索引一个消息队列
#define MSG_PATH "./" //存在的文件夹或文件
#define MSG_PROJ_ID 520 //项目代号 非0整数
#define MSG_TYPE 520 //消息类型
#define MSG_ONE_PACKET_LEN 8*1024
typedef struct
{
char buf[MSG_ONE_PACKET_LEN];
}MsgPrivateData_t;
typedef struct
{
long mtype; //消息类型
MsgPrivateData_t private; //自定义数据
}MsgData_t;
int main(int argc, char *argv[])
{
int ret = -1;
key_t key;
int msg_id;
MsgData_t data;
struct msqid_ds info;
memset(&data, 0, sizeof(data));
key = ftok(MSG_PATH, MSG_PROJ_ID);
if (-1 == key) //-1失败 并设置错误码 0成功
{
printf("ftok fail errno:%d, %s\n", errno, strerror(errno));
return -1;
}
printf("ftok key:%d\n", key);
msg_id = msgget(key, IPC_CREAT | 0777);
if (-1 == key) //-1失败 并设置错误码 >0的整数
{
printf("msgget fail errno:%d, %s\n", errno, strerror(errno));
return -1;
}
printf("msg_id:%d\n", msg_id);
while (1)
{
printf("before msgrcv data\r\n");
msgrcv(msg_id, (void *)&data, sizeof(data.private), MSG_TYPE, 0); //MSG_TYPE 如果为0表示接收最早数据 如果指定消息类型则接收对应类型的最早数据
printf("msgrcv data type:%ld, buf:%s\r\n", data.mtype, data.private.buf);
}
return 0;
}
标签:IPC,队列,system,int,MSG,key,linux,msg
From: https://blog.csdn.net/weixin_43074937/article/details/136701946