消息队列(System V)

一、消息队列概念

消息队列的基本概念消息队列 (也叫做报文队列)是UNIX系统V版本中3种进程间通信机制之一。另外两种是信号灯和共享内存。这些IPC机制使用共同的授权方法。只有通过系统调用将标志符传递给核心之后,进程才能存取这些资源。这种系统IPC对象使用的控制方法和文件系统非常类似。使用对象的引用标志符作为资源表中的索引。

  消息队列就是一个消息的链表。就是把消息看作一个记录,并且这个记录具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读出消息。

  • 消息队列的一些限制:

二、消息队列的主要调用
  • 内核中实现消息传递机制的代码基本上都在文件ipc/msg.c中,消息队列的主要调用有下面4个

  (1)msgget:调用者提供一个消息队列的键标 (用于表示个消息队列的唯一名字),当这个消息队列存在的时候, 这个消息调用负责返回这个队列的标识号;如果这个队列不存在,就创建一个消息队列,然后返回这个消息队列的标识号 ,主要由sys_msgget执行。

  (2)msgsnd:向一个消息队列发送一个消息,主要由sys_msgsnd执行。

  (3)msgrcv:从一个消息队列中收到一个消息,主要由sys_msgrcv执行。

  (4)msgctl:在消息队列上执行指定的操作。根据参数的不同和权限的不同,可以执行检索、删除等的操作,主要由sys_msgctl执行。

  •  每个消息队列都有一个msqid_ds结构与其相关联
struct msqid_ds{
struct      ipc_perm      msg_perm;      //此结构体见XSI标识符中
msgqnum_t       msg_qnum;
msglen_t      msg_qbytes;
pid_t       msg_lspid;
pid_t      msg_lrpid;
time_t    msg_stime;
time_t    msg_rtime;
time_t    msg_ctime;
...........
...........
}//不同的系统中此结构会有不同的新成员
        
三、函数原型

int msgget(key_t key, int msgflg);
功能:创建一个消息队列
参数:
key: 与消息队列关联的键。key是对应于IPC标识符(也就是创建的消息队列的ID)的键值,用于其他进程通过该键值获 得IPC标识符,一个IPC结构对应于一个IPC标识符。key的值还可以是IPC_PRIVATE,IPC_PRIVATE保证创建一个新IPC结构。使用此键值每次都可以创建一个新的IPC结构,并且一个键值对应于很多IPC结构。IPC_PRIVATE这个键值一般为0。
  msgflg   消息队列  的建立标志和存取权限。
IPC_CREAT如果内核中没有此队列,则创建它。
IPC_EXCL当和IPC_CREAT一起使用时,如果队列已经存在,则失败。
0666与open创建文件时的参数一样
返回值:成功执行时,返回    消息队列 标识值。失败返回-1
注:key仅用来让另外一个进程获得一个已创建的IPC标识符,如果单独使用IPC_CREAT,且发现key没有与任何IPC标识符绑定,则msgget()返回一个新创建的     消息队列  的标识符。如果发现key已与一个消息队列标识符绑定,则返回与此key值绑定的队列的标识符。如果IPC_EXCL和IPC_CREAT一起使用,则msgget()要么创建一个新的     消息队列  ,要么如果队列已经存在则返回一个失败值-1。IPC_EXCL单独使用是没有用处的。 key可以自己指定一个唯一的值,还可以由ftok函数生成(见XSI标识符) 

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:将数据放到消息队列中,消息总是放在队列尾端
参数:
msqid:消息队列的标识符,向其发送消息。
msgp:指向消息缓冲区的指针 ,指向一个长整形数,此长整形数包含了正的消息类型,在其后紧跟要发送的消息数据。通常定义一个结构体,形态如下
struct msgbuf {
long mtype; /* 消息类型,必须 > 0 */
char mtext[size]; /* 消息文本 */
};
msgz:要发送消息的大小,也就是要发送  msgz字节的消息
msgflg:这个参数依然是是控制函数行为的标志,取值可以是:0,表示忽略;IPC_NOWAIT,如果消息队列已满,则返回一个ENOMSG。如果不指定这个参数,那么进程将被阻塞下列情况出现为止:有空间可以容纳要发送的消息。从系统中删除此队列。捕捉到一个信号,并从信号处理函数返回。
返回值:成功:0 出错:-1

注:对删除消息队列的处理目前还不是很完善,因为对每个消息队列并没有设置一个引用计数器(对文件则有)。所以删除队列可能造成仍在使用这一队列的进程在下次对队列进行操作时出错返回。而删除一个文件时,要等到该文件的最后一个进程关闭了它的文件描述符后,才会删除文件的内容。

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
功能:读取消息数据,并不一定从头开始接收,按照类型接收
参数:
            msqid:消息队列 的标识符,从其接收消息。
 msgp:指向消息缓冲区的指针, 指向一个长整形数,此长整形数包含了正的消息类型,在其后紧跟要发送的消息数据。通常定义一个结构体,形态如下
struct msgbuf {
long mtype; /* 消息类型,必须 > 0 */
char mtext[ size ]; /* 消息文本 */
};
msgsz: 指定能接收的最大字节数的消息大小。如果 msgflg 设置了MSG_NOERROR,且函数取得的消息长度大msgsz,将只返回msgsz 长度的信息,剩下的部分被丢弃了。如果不指定这个参数,E2BIG 将被返回,而消息则留在队列中不被取出。当消息从队列内取出后,相应的消息就从队列中删除了。 注: msgsz不是要读取的字节数,而是msgp结构体中存放数据缓冲区的最大长度
msgtyp:要读取的消息类型
      msgtyp=0 则返回队列的最早的一个消息。
      msgtyp>0,则返回其类型为mtype的第一个消息。
      msgtyp<0,则返回其类型小于或等于mtype参数的绝对值的最小的一个消息。
msgflg:这个参数依然是是控制函数行为的标志,取值可以是:0,表示忽略;IPC_NOWAIT,如果没有指定类型的消息,则出错返回。 如果不指定这个参数,那么进程将被阻塞下列情况出现为止:有了指定类型的消息, 从系统中删除此队列。捕捉到一个信号,并从信号处理函数返回。
返回值:返回拷贝到mtext数组的实际字节数,失败:-1


int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );
功能:对消息队列执行多种操作
参数:
msgqid:队列的标识符。
cmd:
IPC_STAT
读取消息队列的数据结构msqid_ds,并将其存储在b u f指定的地址中。
IPC_SET
设置消息队列的数据结构msqid_ds中的ipc_perm元素的值。这个值取自buf参数。
IPC_RMID
从系统内核中移走消息队列。
buf:共享内存管理结构体。具体说明参见共享内存内核结构定义部分
返回值:成功返回0,否则返回-1


四、消息队列特性

  • 每当一个消息被读取后,就会消失。
  • 如果msgrcv没有指定IPC_NOWAIT,则在读取某种类型的消息队列为空时,会一直阻塞到有消息进来。如果指定则返回。
  • 造成msgsnd()等待的条件有两种:
           1、 当前消息的大小与当前消息队列中的字节数之和超过了消息队列的总容量;
2、当前消息队列的消息数(单位"个")不小于消息队列的总容量(单位"字节数"),此时,虽然消息队列中的消息数目很多,但  基本上都只有一个字节。
  • 当进程结束后,消息队列仍然存在,除非显式的将其删除,因为它是属于内核级别的一种资源。

五、例程:

msgsnd.c文件:
#include "head.h"

#define  KEY  0x01020304
#define  MAX  1024


typedef struct _mymsg
{
long msgtype;
char msgbuf[MAX];
}Mymsg;

Mymsg msg;



int main(int argc, const char *argv[])
{
int msgid;
if((msgid = msgget(KEY,IPC_CREAT | 0666)) < 0)
ERROR_D("msgget");
msg.msgtype = 1;
while(1)
{
fgets(msg.msgbuf,sizeof(msg.msgbuf),stdin);

if(!strcmp(msg.msgbuf,"quit\n"))
msgctl(msgid,IPC_RMID,NULL);

if(msgsnd(msgid,&msg,strlen(msg.msgbuf)+1,0) < 0)
ERROR_D("msgsnd");
}

return 0;
}


msgrcv.c文件:
#include "head.h"

#define  KEY  0x01020304
#define  MAX  1024


typedef struct _mymsg
{
long msgtype;
char msgbuf[MAX];
}Mymsg;

Mymsg msg;



int main(int argc, const char *argv[])
{
int msgid;
if((msgid = msgget(KEY,IPC_CREAT | 0666)) < 0)
ERROR_D("msgget");

while(1)
{

if(msgrcv(msgid,&msg,sizeof(msg.msgbuf),1,0) < 0)
ERROR_D("msgrcv");
fputs(msg.msgbuf,stdout);
}

return 0;
}











  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值