您的位置:首页 > 运维架构 > Linux

Linux的进程编程-之二-进程间通信(消息队列)

2012-01-02 17:07 423 查看

1.1 系统V消息队列

消息队列中的每个消息都有如下的数据结构:

struct msgbuf

{

long mtype; // 消息类型

char mtext
; // 消息内容,n由用户自己定义

};

1.1.1 ftok( )

#include<sys/types.h>

#include<sys/ipc.h>

key_tftok( const char *name, int id )

参数name指定了文件名(包含路径),该文件必须存在,而且当前进程必须能够访问该文件。

参数id只有低8位有效。

只有当name和id取值都相同时,返回的键值key才是相同的。

成功返回键值,失败返回-1。

1.1.2 msgget( )

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/msg.h>

intmsgget( key_t key, int msgflg )

创建或获取消息队列;成功返回与key相关联的消息队列id,失败返回-1。

参数msgflg可以取IPC_CREAT、IPC_EXCL、IPC_NOWAIT。

单独使用IPC_CREAT,如果不存在与键值key相关联的消息队列,就创建一个新的消息队列,并返回其id,如果已经存在与键值key相关联的消息队列,就返回该消息队列的id。

单独使用IPC_EXCL是没有意义的,如果IPC_EXCL和IPC_CREAT一起使用,当与键值key相关联的消息队列已经存在时,就失败返回-1。

下面两种情况会创建一个新的消息队列:

1.参数msgflg指定IPC_CREAT,而且没有消息队列与键值key相关联;

2.参数key指定IPC_PRIVATE;

参数msgflg的低9位指定新创建消息队列的访问权限:

所有者
组成员
其他成员


执行


执行


执行

1.1.3 msgrcv( )

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/msg.h>

ssize_tmsgrcv( int msqid, void *msgp, size_t msgsz, long int msgtyp, int msgflg );


读取消息队列中的一个消息,存放到msgp指向的msgbuf结构中。

成功返回实际读出消息内容的字节数,并将消息从消息队列中移除;失败返回-1,不移除消息。

msgsz指定读取消息的长度,即msgbuf结构中mtext
的长度。

msgtyp指定读取消息的类型:

msgtyp = 0 读取消息队列中的第一个消息

msgtyp>0 读取消息队列中第一个msgtyp类型的消息,如果没有,失败返回

msgtyp<0 如果消息队列中的最小类型≤abs(msgtyp),读取最小类型的第一个消息;

如果消息队列中的最小类型>abs(msgtyp),失败返回

参数msgflg可以取值:

IPC_EXCEPT :当msgtyp>0时,返回消息队列中第一个类型不是msgtyp的消息。

IPC_NOWAIT

设定 :如果消息队列中没有满足条件的消息,立即失败返回。

未设定 ;如果消息队列中没有满足条件的消息,挂起当前进程,直到以下任一事件发生:

1.满足条件的消息出现在消息队列中,成功返回;

2.消息队列被删除,失败返回。

IPC_NOERROR

设定 :如果消息内容>msgsz,把多余的消息内容清除,成功返回。

未设定 :如果消息长度>msgsz,失败返回。

1.1.4 msgsnd( )

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/msg.h>

intmsgsnd( int msqid, struct msgbuf *msgp, int msgsz, int msgflg );

向消息队列中发送一个消息,消息来源是msgp指向的msgbuf结构。

成功返回0;失败返回-1。

msgsz指定发送消息的长度,即msgbuf结构中mtext
的长度。

参数msgflg可以取值:

IPC_NOWAIT

设定 :如果队列中的消息内容或消息数目已经达到上限,立即失败返回。

未设定 :如果队列中的消息内容或消息数目已经达到上限,挂起当前进程直到任一事件发生:

1.消息内容或消息数目恢复正常,成功返回;

2.消息队列被删除,失败返回。

1.1.5 msgctl( )

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/msg.h>

intmsgctl( int msqid, int cmd, struct msqid_ds *buf );

获取或设置消息队列的属性,成功返回0;失败返回-1。

参数cmd可以指定三种操作:

IPC_RMID :删除指定的消息队列。

IPC_STAT :用来获取消息队列的信息,返回的信息存放到buf指向的msqid_ds结构中。

IPC_SET :用来设置消息队列的属性,要设置的属性存储在buf指向的msqid_ds结构中。

1.2 Posix消息队列

1.2.1 消息队列的创建和删除

1.2.1.1 mq_open( )

#include<mqueue.h>

mqd_tmq_open( const char *name, int flag )

mqd_t mq_open( const char *name, int flag, mode_t mode, mq_attrattr )

创建或获取一个消息队列。成功返回消息队列描述符;失败返回-1。

参数name指定与消息队列相关联的名字。

参数flags可以取:

O_RDONLY O_WRONLY O_RDWR(三选一)

O_CREAT

单独使用O_CREAT,如果不存在与name相关联的消息队列,就创建一个新的消息队列,并返回其描述符,如果已经存在与name相关联的消息队列,就返回该消息队列的描述符。

如果指定了O_CREAT,需要使用mq_open( )的第二种形式,其中参数mode指定了新创建消息队列的访问权限,参数attr指定了新创建消息队列的属性。

O_EXCL。

单独使用O_EXCL是没有意义的,如果O_EXCL和O_CREAT一起使用,当与name相关联的消息队列已经存在时,就失败返回。

O_NONBLOCK

决定在mq_send( )和mq_receive( )时是否会挂起当前进程,直到读取或发送消息成功。

1.2.1.2 mq_close( )

#include <mqueue.h>

int mq_close( mqd_t mqdes )

关闭当前进程和指定消息队列之间的联系。

成功返回0,失败返回-1。

1.2.1.3 mq_unlink( )

#include <mqueue.h>

int mq_unlink( const char *name )

删除指定的消息队列,但是如果当前仍有其它进程正在使用消息队列,则暂时放弃删除操作,并立即返回,直到其它进程通过调用mq_close( )关闭之后,再进行删除操作。

成功返回0,失败返回-1。

1.2.2 消息队列的属性

1.2.2.1 mq_getattr( )

#include<mqueue.h>

intmq_getattr( mqd_t mqdes, struct mq_attr *attr )

成功返回0,失败返回-1。

struct mq_attr

{

long mq_flags; //message queue flags

long mq_maxmsg; //maximum number of messages

long mq_msgsize; // maximummessage size

long mq_curmsgs; // numberof messages currently queued

}

1.2.2.2 mq_setattr( )

#include<mqueue.h>

intmq_setattr( mqd_t mqdes, const struct mq_attr *newAttr, struct mq_attr *oldAttr)

注意:只能设定mq_attr结构中的mq_flags,mq_attr结构中的其它成员将被忽略。

成功返回0,失败返回-1。

1.2.3 消息队列的操作

1.2.3.1 mq_notify()

#include<mqueue.h>

int mq_notify( mqd_t mqdes, const struct sigevent*notification )

成功返回0,失败返回-1。

为当前进程在指定的消息队列上注册notify操作,当消息队列由空变为非空时,也就是说有消息加入原本为空的消息队列时,会触发进程注册的nofity操作。

参数notification指定需要注册的nofity操作。如果参数notification为NULL,而且进程之前注册过notify操作,会取消之前注册的notify操作。

需要注意的是:

1.只能有唯一的一个进程在消息队列上注册notify操作。如果已经有其它进程在消息队列上注册了notify操作,试图再次进行notify()会失败返回;

2.当进程注册的nofity操作被触发之后,该nofity操作就会被删除,其它进程可以重新向该消息队列注册notify操作。

如果进程已经注册过notify操作,而且进程在消息队列为空时,阻塞调用了mq_receive( )(即在mq_open()时设定了O_NONBLOCK),如果有一个消息到达,会先满足mq_receive( )调用,所以消息队列仍然为空,不会触发notify操作。

struct sigevent

{

int sigev_notify;

int sigev_signo; // signal numbersent to current process when the timer expires

union sigval sigev_value; // info carried with signal

NotifyFUN sigev_notify_function; //typedef void (*NotifyFUN)( union sigval)

pthread_attr_t* sigev_notify_attributes;

}

sigev_notify的取值:

SIGEV_NONE :No notification will be delivered when the event ofinterest occurs.

SIGEV_SIGNAL :A queued signal will be generated when theevent of interest occurs.

SIGEV_THREAD :A notification function will be called toperform notification.

1.2.3.2 mq_receive( )

#include<mqueue.h>

ssize_tmq_receive( mqd_t mqdes, char *msg, size_t len, unsigned int *prio )

读取the oldest of the highest priority message。

参数len指定读取消息的长度,如果len<attr(mq_msgsize),失败返回。

mq_open( )是否设定O_NONBLOCK,会决定mq_receive( )是否进行阻塞读取。

成功返回读取消息的字节数,失败返回-1。

1.2.3.3 mq_send( )

#include<mqueue.h>

intmq_send( mqd_t mqdes, const char *msg, size_t len, unsigned int prio )

参数len指定发送消息的长度,如果len>attr(mq_msgsize),失败返回。

参数prio<MQ_PRIO_MAX。

mq_open( )是否设定O_NONBLOCK,会决定mq_send( )是否进行阻塞发送。

成功返回0,失败返回-1。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐