芒果tv mbc投票网址:IPC SystemV Message Queue

来源:百度文库 编辑:九乡新闻网 时间:2024/04/29 00:02:13
SystemV消息队列
1、 函数列表
Ø        key_t ftok(const char *pathname,int proj_id);
//# include
//# include
IPC消息队列有一个key的属性(类型为key_t),一般由此函数产生,产生方法为:根据文件名pathname(必须存在且有权限访问)得到索引节点号,然后将索引节点号和子序列号(proj_id)组成ID标示。
Ø        int msgget(key_t key, int msgflg);
#include
#include
#include
此函数有两个作用:创建key属性为key的消息队列和返回key指定消息的msgid,其中msgid是消息队列的标示。
其中msgflg标示符可以指定创建消息队列的访问权限(一般为S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH用户读写,组和其它读);同时可以指定msgget函数执行的操作,在创建消息队列时,msgflg必须有IPC_CREAT。
如果msgflg为0,则只返回消息队列的msgid。
此函数成功时,返回非负消息队列标示;失败时返回-1。
Ø        int msgsnd(int msqid, const void*msgp, size_t msgsz, int msgflg);
#include
其中msgid是msgget返回的消息队列标识符,msgp是一个结构体指针,msgsz是结构体中具体数据的长度,msgflg可以为0或者IPC_NOWAIT。
当msgflag指定IPC_NOWAIT时,msgsnd函数成为非阻塞,当由于一些限制条件(例如没有存放消息的可用空间时)出现时,该函数立即放回。
发送成功返回0,发送失败返回-1.
Ø        ssize_t msgrcv(int msqid, void*msgp, size_t msgsz, long msgtyp, int msgflg);
msgsz是结构体(msgp)中保存数据的最大值,也是函数能够返回的最大数据量。而具体的接收的数据量,由函数返回值确定。msgflag可以为0或者IPC_NOWAIT。msgtyp指定待接收消息的类型。
当msgflag指定为IPC_NOWAIT时,msgrcv函数成为非阻塞,当由于一些限制条件(例如消息队列中没有消息)时,该函数立即返回。
其中type的规则为:
当type=0时,返回消息队列中的第一个消息;
当type>0时,返回类型值为type的消息;
当type<0时,返回类型值小于或者等于type绝对值的消息中类型值最小的消息。
msgrcv函数成功时返回接收消息的数据量,失败返回-1.
Ø        int msgctl(int msqid, int cmd,struct msqid_ds *buf);
消息队列控制函数。Msgid为消息队列标示,cmd为具体的命令(一共有三种),buf用来设置或取得消息队列的msgid_ds结构体。
IPC_RMID:删除msgid指定的消息队列。Buf参数忽略,为0
IPC_SET:设置消息队列msgid_ds结构体的四个成员:msg_perm.uid,msg_perm_gid,msg_perm.mode和msg_qbytes。它们的值来自由buf指向的结构体中的相应成员。
IPC_STAT:给调用者返回消息队列msgid_ds结构体,通过buf返回。
2、 实例解析
Ø        create|send|receive|remove
消息队列的创建和删除、消息的发送和接收。采用默认的structmsgbuf作为消息体。
// mymsgcreate.c
#include    
#include // O_CREATE
#include // pid_t
#include    
int main(int argc, char **argv)
{
int              c, oflag, mqid;
oflag = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH | IPC_CREAT;
//设置权限(用户读写,组和其它读)
//指定msgget具体操作(创建消息队列并返回ID)
if((mqid = msgget(ftok("test3", 0), oflag))<0)
printf("create error!\n");
//ftok的pathname参数所指向的文件必须存在
printf("mqid===%d\n",mqid);
exit(0);
}
//#gcc mymsgcreate.c –o mycreate
创建一个消息队列必须满足的条件是:ftok函数的pathname指向的文件已经存在;msgflg中有IPC_CREATE标示。权限要设置正确,用户要有读和写权限。
// mymsgsnd.c
#include    
#include // O_CREATE
#include // pid_t
#include    
int
main(int argc, char **argv)
{
struct msgbuf      *ptr;
int     mqid;
if((mqid = msgget(ftok("test3", 0), S_IWUSR))<0)
printf("create error!\n");
// S_IWUSR权限可以省略,消息队列的权限已经设置了,这里可以为0
//msgget函数的作用是返回消息队列的ID
ptr = calloc(sizeof(long)+7, sizeof(char));
ptr->mtype = 100;
strcpy(ptr->mtext,"abcdefg");
msgsnd(mqid, ptr,7, 0);
exit(0);
}
// gcc -D_GNU_SOURCE mymsgsnd.c -o mysend
消息队列已经创建了,此时msgget函数只是起获得消息队列标示的作用,因此msgflg可以为0。
关于编译选项-D_GNU_SOURCE说明如下:
/usr/include/src/msg.h文件中
#ifdef __USE_GNU
/* Template for struct to be used as argument for `msgsnd' and `msgrcv'. */
struct msgbuf
{
long int mtype; /* type of received/sent message */
char mtext[1]; /* text of the message */
};
#endif
#ifdef _GNU_SOURCE
# define __USE_GNU 1
#endif
因此要想使用structmsgbuf,必须#define _GNU_SOURCE,也可以通过编译选项加进去。
注意msgbuf成员mtext是大小为1的字符数组,而经测试:消息数据的长度不受此限制。例如上面的例子即发送了7个字符。这可能是与结构体成员内存存储有关,也就是可能已经超出结构体的存储范围,这对普通的数据类型是不允许,但对结构体变量是可以的,正如 strcpy(ptr->mtext,"abcdefg");操作是合法的。
//mymsgrec.c
#include    
#include // O_CREATE
#include // pid_t
#include    
#define       MAXMSG         (8192 + sizeof(long))
int
main(int argc, char **argv)
{
int     mqid,n;
struct msgbuf       *buff;
if((mqid = msgget(ftok("test3", 0), S_IRUSR))<0)
printf("create error!\n");
//S_IWUSR权限可以省略,消息队列的权限已经设置了,这里可以为0
//msgget函数的作用是返回消息队列的ID
buff = malloc(MAXMSG);
n =msgrcv(mqid, buff, MAXMSG, 100, 0);
printf("read %d bytes, type = %ld,mtext=%s\n", n, buff->mtype,buff->mtext);
exit(0);
}
// gcc -D_GNU_SOURCE mymsgrec.c -o myrec
通消息发送,此时消息队列已经创建,msgget函数只起获得消息队列标示的作用,msgflg可以为0.
//mymsgrmid.c
#include    
#include // O_CREATE
#include // pid_t
#include    
int
main(int argc, char **argv)
{
int              mqid;
mqid = msgget(ftok("test3", 0), 0);
msgctl(mqid, IPC_RMID, 0);
exit(0);
}
//gcc mymsgrmid.c –o myrm
struct msqid_ds *buf参数被忽略,为0。
Ø        mystruct
自定义消息结构体进行消息的发送和接收。
msgsnd和msgrcv函数的void* msgp是具有struct msgbuf模板的结构体变量。
首先分析下struct msgbuf的结构。
struct msgbuf
{
long int mtype; /* type of received/sent message */
char mtext[1]; /* text of the message */
};
有两个成员,一个为long int保存着消息类型,一个为char数组,保存着具体的消息数据。
因此,以此结构体作为模板的结构体至少有两个成员,一个为long int,一个为char数组。如果结构体的成员变量不只这两个,必须保证保存消息类型的long int和保存消息数据的char数组,连续存储,并位于结构体末尾。
现在自定义一个以struct msgbuf为模板的结构体。
struct mymesg {
long        mesg_len;   /* #bytes in mesg_data, can be 0 */
long        mesg_type;         /* message type, must be > 0 */
char        mesg_data[MAXMESGDATA];
};
int msgsnd(int msqid, const void *msgp,size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_tmsgsz, long msgtyp, int msgflg);
两个函数中msgp结构体指针为部分mymesg结构体指针,指向mseg_type。也就是消息接收和发送函数的void* msgp参数为&(ptr->mesg_type)。也就是消息传输的结构体不包含mesg_len成员数据,在接收端,mesg_len通过msgrcv函数的返回值确定。
从实现方式和结果来看,使用structmsgbuf和自定义结构体没有差异。
//mymesg.h
#include    
#include // O_CREATE
#include // pid_t
#include    
#include
#define       MAXMESGDATA     (PIPE_BUF - 2*sizeof(long))
#define       MESGHDRSIZE         (sizeof(struct mymesg) - MAXMESGDATA)
struct mymesg {
long        mesg_len;   /* #bytes in mesg_data, can be 0 */
long        mesg_type;         /* message type, must be > 0 */
char        mesg_data[MAXMESGDATA];
};
//mystructsnd.c
#include "mymesg.h"
int main(int argc, char **argv)
{
struct mymesg    *ptr;
int     mqid;
if((mqid = msgget(ftok("test3", 0), S_IWUSR))<0)
printf("create error!\n");
ptr = calloc(2*sizeof(long)+7, sizeof(char));
ptr->mesg_type = 100;
ptr->mesg_len  = 7;
strcpy(ptr->mesg_data,"abcdefg");
msgsnd(mqid, &(ptr->mesg_type),ptr->mesg_len, 0);
exit(0);
}
// gcc -D_GNU_SOURCE mystructsnd.c -o mystructsend
// mystructrec.c
#include "mymesg.h"
#define       MAXMSG         (8192 + sizeof(long))
int
main(int argc, char **argv)
{
int     mqid,n;
struct mymesg      *buff;
if((mqid = msgget(ftok("test3", 0), S_IRUSR))<0)
printf("create error!\n");
buff = malloc(MAXMSG);
buff->mesg_type=100;
n =msgrcv(mqid,&(buff->mesg_type), MAXMSG,buff->mesg_type, 0);
buff->mesg_len=n;
printf("read %d bytes, type = %ld,mtext=%s\n", buff->mesg_len, buff->mesg_type,buff->mesg_data);
exit(0);
}
// gcc -D_GNU_SOURCE mystructrec.c -o mystructrec
3、 小结
Ø        消息队列和管道(pipe和FIFO)的区别:
管道可以比作为“传输带”,货物(数据流)是按照放上去的顺序达到的;
消息队列可以比作为“仓库”,货物是静态地存储的。
管道对于存货和取货的双方有一定的要求:没有存货方,就不能有取货方(管道只能先以写方式打开后,才能以读方式打开);没有货,就不能取货(对管道写数据后,才能读数据);并且对货物形式有要求(存货和取货双方必须定义一致的数据协议)。
消息队列的取货和存货方不存在彼此阻塞约束的现象,双方都是独立自由的,消息队列只是一个公共的存货的仓库;双方也不需要关心数据协议,消息队列已经将数据以消息形式保存在队列中。
Ø        Posix消息队列和SystemV消息队列区别
新的应用程序应考虑使用Posix消息队列,不过大量的现有代码使用SystemV消息队列。
Posix消息队列遗漏的主要特性是从队列中读取指定优先级消息的能力;这两种消息都不适用真正的描述字,因此从而造成在消息队列上使用select或poll的困难。
Ø        ipcs命令
此命令用于显示系统中进程间通信的内核对象。
#ipcs –qa
显示所有的进程间通信对象
#ipcs –q
显示消息队列对象
Ø        消息复用是指在一个消息队列上存储多个种类的消息,这些消息通过struct msgbuf的mtype来区分。
Ø        消息队列存在一定的限制,包括:每个消息的最大字节数;任何一个消息队列上的最大字节数;系统范围的最大消息队列数;系统范围的最大消息数。