System V消息队列
目录
1. 概述
System V消息队列使用消息队列标识符标识,和Posix消息队列一样,发送消息和接收消息的线程(进程)是相互独立、互不依赖的。
对于系统中的每个消息队列,内核维护一个定义在sys/msg.h头文件中的结构,其中带注释的是我们需要关注的成员变量。
struct msqid_ds
{
struct ipc_perm msg_perm;
struct msg *msg_first; //指向队列中第一条消息
struct msg *msg_last; //指向队列中最后一条消息
msglen_t msg_cbytes; //消息队列当前第几个字节
msgqnum_t msg_qnum; //消息队列当前第几条消息
msglen_t msg_qbytes; //消息队列允许的最大字节数,仅针对消息数据,不包括与每个消息关联的长整型消息类型
pid_t msg_lspid;
pid_t msg_lrpid;
time_t msg_stime;a
time_t msg_rtime;
time_t msg_ctime;
};
2. 消息队列API
msgget
msgget用于创建一个新的消息队列或访问一个已存在的消息队列,参数key和oflag的含义及使用方法和semget一样,不再赘述。
//成功返回消息队列标识符,失败返回-1
int msgget(key_t key, int oflag);
msgsnd
msgsnd用于向消息队列中添加一条消息。
//成功返回0,失败返回-1
int msgsnd(int msqid, const void *ptr, size_t length, int flag);
参数说明:
- msqid是msgget返回的标识符
- ptr是一个由应用程序按如下模板定义的struct sembuf结构指针,只要保证第一个成员变量是long type即可,其后的数据部分可根据需要任意扩展
struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
- length是待发送消息的长度,即消息类型之后的用户自定义数据的长度,该长度可以是0
- flag可以是0或者IPC_NOWAIT,一般设为0
msgrcv
msgrcv用于从消息队列中取出一条消息。
//成功返回实际读入缓冲区的数据长度,失败返回-1
int msgrcv(int msqid, void *ptr, size_t length, long type, int flag);
参数说明:
- msqid是msgget返回的标识符
- ptr指向数据接收缓冲区,它应该和msgsnd的ptr具有同样的struct sembuf结构
- length为缓冲区大小
- type用于指定希望从消息队列中读出什么样的消息
- flag可以是0、IPC_NOWAIT或MSG_NOERROR,一般设为0
msgrcv第四个参数type用于指定希望从消息队列中读出什么样的消息,假设有消息队列中有三条消息:
- 第一条消息的类型为100,长度为1
- 第二条消息的类型为200,长度为2
- 第二条消息的类型为300,长度为3
那么:
- type = 0:返回队列中第一个消息
- type > 0:返回消息类型等于type的第一个消息
- type < 0:返回消息类型 <= abs(type)的消息中类型值最小的第一个消息
msgctl
msgctl提供在一个消息队列上的各种控制操作。
//成功返回0,失败返回-1
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
msgctl支持三个cmd命令:
- IPC_RMID:从系统中删除由msqid指定的消息队列,此时第三个参数被忽略,设为NULL即可
- IPC_STAT:通过buf参数返回由msqid指定消息队列对应的msqid_ds结构
- IPC_SET:通过buf参数返回由msqid指定消息队列对应的msqid_ds结构,但仅设置以下4个成员:msg_perm.uid、msg_perm.gid、msg_perm.mode和msg_perm.qbytes
3. 简单的程序
代码实现
common.h
#ifndef _COMMON_H_
#define _COMMON_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define FTOK_FILE "/home/delphi/ftok.file"
#define FTOK_ID 1
#define MSG_RD_PERMISSION 0444
#define MSG_WR_PERMISSION 0222
#define MSG_RW_PERMISSION (MSG_RD_PERMISSION | MSG_WR_PERMISSION)
#define MAX_MSG_LEN (8192 + sizeof(long))
struct msgbuf
{
long type;
char *data;
};
#endif
msgcreate.c
#include "common.h"
int main()
{
key_t key = ftok(FTOK_FILE, FTOK_ID);
int oflag = IPC_CREAT | MSG_RW_PERMISSION;
int msgid = msgget(key, oflag);
if (msgid >= 0)
{
printf("msgget create success, msgid = %d\n", msgid);
}
return 0;
}
msgsnd.c
#include "common.h"
int main(int argc, char **argv)
{
int msgid;
int msglen;
long msgtype;
struct msgbuf *msg;
msgid = msgget(ftok(FTOK_FILE, FTOK_ID), MSG_WR_PERMISSION);
msglen = atoi(argv[1]);
msgtype = atol(argv[2]);
msg = (struct msgbuf *)calloc(sizeof(long) + msglen, sizeof(char));
msg->type = msgtype;
msgsnd(msgid, msg, msglen, 0);
return 0;
}
msgrcv.c
#include "common.h"
int main(int argc, char **argv)
{
int msgid;
int rcvlen;
long msgtype;
struct msgbuf *msg;
msgid = msgget(ftok(FTOK_FILE, FTOK_ID), MSG_RD_PERMISSION);
msgtype = atol(argv[1]);
msg = (struct msgbuf *)calloc(MAX_MSG_LEN, 1);
rcvlen = msgrcv(msgid, msg, MAX_MSG_LEN, msgtype, 0);
printf("read %d bytes, type = %ld\n", rcvlen, msg->type);
return 0;
}
msgrmid.c
#include "common.h"
int main(int argc, char **argv)
{
int msgid = msgget(ftok(FTOK_FILE, FTOK_ID), 0);
msgctl(msgid, IPC_RMID, 0);
return 0;
}