Posix消息队列_第1页
Posix消息队列_第2页
Posix消息队列_第3页
Posix消息队列_第4页
Posix消息队列_第5页
免费预览已结束,剩余12页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Linux3+1 暑期学习总结三(Posix 消息队列)王晶晶一,消息队列简介:消息队列可以看作是一个消息连表。它具有随内核的持续性,即当使用该消息队列的进程结束,或者已关闭该消息队列,该队列中的消息不会随之消失,只有在内核重新初始化,即计算机重启之后才会消失,因此称为随内核的持续性,这点也是与管道和 FIFO 的区另 I。消息队列的另一个特性是,在某一个进程往消息队列写消息之前不需要另外某个进程在该消息队列上等待消息的到达,即不会像管道个 FIFO 那样,如果往管道或者 FIFO 中些数据时,如果没有一个进程已经将读端打开,那么写操作会被阻塞。当然,如果从消息队列读取数据时,消息队列为空是会

2、阻塞的。每个消息都是一条记录,它有发送者赋予一个优先权,值越大优先级越高。下图为一个消息队列可能的布局:该链表的头中含有当前队列的两个属性:队列中允许的最大消息数,每个消息的最大大小。二,相关函数解释:1.mq_open所在头文件:#include函数原型:mqd_tmq_open(constchar*name,int0flag,.mode_tmode,structmq_attr*attr);函数功能:创建消息队列。参数说明:name 为消息队列的名字,根据消息队列的规则,为了更好的可移植性,该名字必须以,/所头,创建一个消息队列的时候无须路径,给出名字就好,其存放位置可有自己指定(创建前后都

3、可以,下面会讲到)。oflag:为 O_RDONLY(只读),O_WRONLY(只写),O_RDWR(可读可写)之一,可能安位或上 O_CREATE,O_EXCL(当消息已存在时,返回 EEXIST 错误到 errno 中),O_NONBLOCK(设置非阻塞)。mode 和 attr 参数是可选,但是当实际操作是创建一个新队列时,即 O_CREATE 已指定,且要求创建的消息队列不存在,mode 和 attr 参数是需要的。mode:表示创建消息对列的权限。由S_IRUSR,S_IWUSR,S_IXUSR,S_IRGRP,S_IWGRP,S_IXGRP,S_IROTH,S_IWOTH,S_IX

4、OTH相或组成或者写成 0777(表示 rwxrwxrwx)等用八进制表示也可以。attr:在 linux 内核源代码中 struct_mqattr 定义的源代码如下:structmq_attrlongtongmq_inaxiTisg;longmq.msgsize;longrinsgs;lungreserved;存放消息队列的属性。其中 mq_flags 为 0,表示阻塞,为 O_NONBLOCK 为非阻塞。函数返回值:在内核源代码中 mqd_t 类型的定义如下:typedef_kernel_mqd_tmqd_t;typedefint_kernel_mqd_t;若创建成功则返回消息队列的描述符

5、,否则返回一 1。所在头文件:#include函数原型:intmq_close(mqd_tmqdes);函数功能:关闭已打开的消息队列,关闭后调用进程不可以再使用该描述符,但其消息队列并没有被删除。一个进程终止时,它的所有打开着的消息队列都关闭,就像调用了mq_close 一样。参数说明:mqdes 为消息队列的描述符,即消息队列创建成功后的返回值。返回值:成功返回 0,失败返回-1。3 .mq_unlink 函数所在头文件:#include函数原型:intmq_unlink(constchar*name);函数作用:从系统中删除名为 name 的消息队列。但删除的只是我们可以在系统中看见的文

6、件的名字,但文件本身并没有被从磁盘上删除,除非该名称是文件的最后一个链接,并且该文件已关闭,才会将该文件真正从磁盘上删除。即如果某前该详细队列的文件还在其他进程中打开,那么不会将其从磁盘上删除,又或者这是最后一个链接,但它还为关闭,即未执行 ma_close 操作,或打开它的进程为结束就执行 mq_unlink,它也不会从磁盘上删除。函数的参数:消息队列的名称,以,/叫始。函数的返回值:成功返回 0,出错返回一 1。4 .mq_getattr 函数所在头文件:#include函数原型:intmq_getattr(mqd_tmqdes,structmq_attr*attr);函数功能:获取 mq

7、des 指的消息队列的属性,存放到 attr 结构体中。参数说明:mqdes 为消息队列描述符,attr 为上面解释的存放消息队列属性的结构体。函数返回值:成功返回 0,失败返回一 1。5 .mq_setattr 函数:所在头文件:#include函数原型:intmq_setattr(mqd_tmqdes,conststructmq_attr*attr,structmq_attr*oattr);函数功能:设置消息队列的属性,但是只使用 attr 结构体中的 mq_flags 属性,以设置(O_NONBLOCK)或清除(0)非阻塞标志。该结构体的另外三个属性被忽略,每个队列的最大消息数和每个消息

8、的最大字节数都只能在创建时设置,当前队列中的消息数是随传送消息和读取消息的操作改变的,只能读取不能设置。如果 oattr 非空,那么指定队列的先前属性(4个)全将返回到由该指针指向的结构体中。参数说明:见上述函数功能中对 attr 和 oattr 的解释。返回值:成功返回 0,失败返回一 1。6 .mq_send 函数:所在头文件:#include函数原型:intmq_send(mqd_tmqdes,constchar*ptr,size_tlen,unsignedintprio);函数功能:给描述符 mqdes 指向的消息队列发送消息,大小为 len,内容存放在 ptr中,prio 为优先级。

9、参数说明:mqdes 为要发送消息的消息队列描述符,ptr 为要发送的数据,len 为消息的长度,prio 为消息的优先级。返回值:成功返回 0,失败返回一 1。7 .mq_receive 函数:所在头文件:#include函数原型:ssize_tmq_receive(mqd_tmqdes,char*ptr,size_tlen,unsignedint*proip);函数功能:从描述符 mqdes 指向的消息队列中读取消息存放 ptr 中。参数说明:mqdes 为要从中读取消息的消息队列的描述符,ptr 为存放接受到的消息的指针,len 为接受的最大长度,该值不能小于能加到该消息对列上的最大大小

10、,如果 len 小于该值,就立即返回 EMSGSIZE 错误。返回值:成功返回读取消息的内容的字节数,出错返回一 1。8 .mq_notify 函数:所在头文件:#include,#include函数原型:intmq_notify(mqd_tmqdes,conststructsigevent*notification);函数功能:为指定队列建立或删除异步事件通知。参数说明:在中:typedefunionsigvalintsival_int;void_user*sival_ptr;sigval_t;typedefstructsigeventsigval_tsigev_value;intsigev

11、_signo;intsigev_notify;void(*sigev_notify_function)(unionsigval);Pthread_attr_t*sigev_notify_attributes;sigevent_t;(1) .如果 notification 参数非空,那么当前进程希望在有一个消息到达所指定的先前为空的队列时得到通知。我们说该进程被注册为接收该队列的通知(2) .如果 notification 参数为空指针,而且当前进程目前被注册为接收所指定队列的通知,那么已存在的注册将被撤销。(3) .任意时刻只有一个进程可以被注册为接收某个指定队列的通知。(4) .当有一个消息

12、到达某个先前为空的队列,而且已有一个进程被注册为接收该队列的通知时,只有在没有任何线程阻塞在该队列的 mq_receive 调用中的前提下,通知才会发出。这就是说,在 mq_receive 调用中的阻塞比任何通知的注册都优先。(5) .当该通知被发送给它的注册进程时,其注册即被撤销。该进程必须再次调用 mq_notify重新注册(如果想要的话)。返回值:成功返回 0,失败返回一 1。三,相关程序示例:mq_create.c#include#include#include#include#include#include#includestructmq_attrattr;intmain(intar

13、gc,char*argv)intc,flags;mqd_tmqd;flags=O_RDWR|O_CREAT;/emz 表示命令行的选项,m 和 z 带有参数,getopt 在我博客有详解while(c=getopt(argc,argv,em:z:)!=-1)switch(c)casee:flags|=O_EXCL;break;casem:attr.mq_maxmsg=atol(optarg);break;casez:attr.mq_msgsize=atol(optarg);break;if(optind!=argc-1)(perror(optinderror!n);)if(attr.mq_ma

14、xmsg!=0&attr.mq_msgsize=0)|(attr.mq_maxmsg=0&attr.mq_msgsize!=0)(perror(mustspecifyboth-mmaxmsgand-zmsgsize!n);)mqd=mq_open(argvoptind,flags,0644,(attr.mq_maxmsg!=0)?&attrNULL);if(mqd!=-1)printf(createok!n);mq_close(mqd);/mq_close 只是关闭了描述符,并不删除消息队列)elseprintf(createerror!n);exit(0);运行过程及

15、结果:wjJBpanda-G31M-ES2C:/linuxJ+1ZtestCode/PosixSwjjfpanda-63lM-ES2C:/linux3+1/testCode/PosixScreateerror!wjjtpanda-G31MES2C/llnux5+1/testCode/PosixtwjjPpanda-1M-ES2C:/linux54-1/testCode/Posixt8192wjjBpanda-631R-ES2Cr/linuxS+1/testCode/Posixtcreateerror!wjjfpanda-GJ1M-ES2C:/linuxS+1ZtestCode/Posixtcr

16、eateok!wjjtpandd-G31M-ES2C:/linuxl+1/testCode/PosixS从上可以看出,创建一个消息队列时,其最大消息数和每个消息的最大字节数不能超出,系统的 msg_max 和 msgsize_max,否则创建失败。当然每个系统对应的这两个值都不同,可通过上面的 cat 路径进行查看。/mq1 创建失败是因为在这之前已经创建了一个/mq1,e 选项就是用来判断当创建的消息队列存在时,返回错误信息。编译时在最后一定要加上-Irt,表示链接。在消息队列的名字前一定要加/,这是 Posix 的规定,为了更好的可移植性。接下来我们要对消息队列进行挂载,只有挂载后你才能看

17、见你的消息队列:gccmqcreate,c-omqcreate-Irt./iriqcreate-e-m3r1B24cat/proc/sys/f5/mqueue/m$g,maxcat/proc/sys/fs/mqueue/msgsize_iiiax.Zmqcreate-e-m8-z1024/mql./mqcreate-e-m8-z1024/mq2文件旧编辑旧查看忖搜索文件旧编辑旧查看忖搜索终端终端帮则帮则H)rootepanda-G31M-ES2C:/home/wjj/linux34-Vtestcode/Posiximount-tmqueuenonemqueuerootpanda-G3IM-ES

18、2C:/home/wjj/linux54-1/testCode/PosixiexiteKitwjjpanda-G51N-ES2C:/linux3+1/testCade/Posix$Is-Inqueue总用星总用星0-rw-r-r-1wjjwjj8Q2011-08-03。9:g6mq1-1wjjB2311-98-04g:12mq2,可以看到在程序的最后调用的 mq_close,但并未删除消息队列的名字,只是关闭了描述符,这是 mq_close 和 mq_unlink 的最大区别。mqunlink.c#include#include#include#include#includeintmain(i

19、ntargc,char*argv)intflag;if(argc!=2)perror(usage:maunlink);flag=mq_unlink(argv1);if(flag=-1)printf(fail!n);elseprintf(ok!n);exit(0);运行过程及结果:wjj电电pan而而-GE1M-EG2c广广/Linux3+ItswtCod白白Posixtgccmqurlink.c-omqunlink-l.rtwjjCpanda-G31M-ES2C:/linux3+1/testCode/PosixtIs-1mqueue总用量总用量0- rw-r-r-1wjjwjj302011-0

20、8-0509:17mqi- rw-r-r-1wjjwjjB0.2011-08-03&9:12mq2wjj*panda-631M-ES2Cr/linux3+1/testCode/Posix$./mqunlinkZmqiok!wjjepanda-GilM-ES2C:/linux3+1/testcode/PosixtIs-Imqiueue总用量总用量0- rw-r-r-1wjjwjj8a2811-00-fl3。9:12叫叫2wjjepanda-G51MES2Cr/linux5+1/testCode/Posixt|mqsend.c#include#include#include#include

21、#include#include#include#includeintmain(intargc,char*argv)mqd_tmqd;char*ptr;size_tlen;unsignedintprio;if(argc!=4)perror(./mqsendmqueue_namesizeprio!n);len=atoi(argv2);prio=atoi(argv3);mqd=mq_open(argv1,O_WRONLY);ptr=(char*)calloc(len,sizeof(char);strcpy(ptr,wjj_xyd);mq_send(mqd,ptr,len,prio);exit(0)

22、;mqreceive.c#include#include#include#include#include#includeintmain(intargc,char*argv)(intc,flags;mqd_tmqd;ssize_tn;unsignedintprio;char*buff;structmq_attrattr;flags=O_RDONLY;while(c=getopt(argc,argv,n)!=-1)(switch(c)casen:flags|=O_NONBLOCK;break;if(optind!=argc-1)perror(mqreceiveerror!n);mqd=mq_ope

23、n(argvoptind,flags);mq_getattr(mqd,&attr);buff=(char*)malloc(attr.mq_msgsize);n=mq_receive(mqd,buff,attr.mq_msgsize,&prio);printf(buff=%s,read%ldbytes,priority=%un,buff,(long)n,prio);exit(0);mqsen.c 和 mqreceive.c 的运行过程和结果:卜面往一个消息队列中写入多条消息,然后读取,会发现读取的结果是按优先级从高到低(因为mq_receive 的 priop 指针不空):wjj

24、panda-G31M-ES2C:/linux3+1ZtestCode/Posixt./inqsend/mql10012wjjSpanda-G31M-ES2C:/linuxS+1/testCode/Posix$./inqsend/mql5。6wjjCpanda-631M-ES2C:/linuxS+1ZtestCode/PosixJ./mqsend/mql568wjjpanda-G31M-ES2C:/linux34-1/testCode/Posix$,/mqreceice/mqlbuff=wjj_xyd,read100bytes,priority-12wjjpanda-G31H-ES2C:Zlin

25、ux3+1/testCode/PosixS,/mqreceice/mqlbuff-wjj_xyd,read50bytes,priority=8wjjepanda-G31H-ES2C:/linuxS+1/testCode/Posix$./mqreceice/mqlbuff=wjj_xyd,read5。bytes,priority=6wjjSpanda-G31M-ES2C:/linuxS+1/testCode/Posixt|下来是一个简单的信号通知的程序,通过 mq_notify 函数实现:mqnotifysigl.c:#include#include#include#include#includ

26、e#includemqd_tmqd;void*buff;structmq_attrattr;structsigeventsigev;staticvoidsig_usr1(int);wjjpanda-G31M-ES2C:/linuxJ+17testcode/PosixSwjjflpanda-G31M-ES2C:/linux3+Vtestcode/Posixlwjjfpanda-G31M-ES2:/linuxi+1/testCode/Poslxl总用量总用量0- rw*r-r-1wjjwjj802011-6B-0369:12mq2- rw-r-r-1wjjwjj802011-08-0389:28m

27、q3wjjpanda-G3lH-ES2C:/linux3+1/testCode/Posixicreateok!wjjBpanda-G31M-ES2C:/linuxi4-1/testcode/PosixSwjjpanda-G31H-ES2C:/linux3+1/testcode/Posix(wjj#panda*G5iH-ES2C/LinuxS+1/testCode/Posix$wjjBpanda-G3IM-ES2C:/liilUxi4-1ZtestCode/PosixS总用量总用量0- rw*r-r-1wjjwjj8ft?0il-08-0369:50mqi- rw-r-r-1wjjwjj8020

28、11-08-0309:30mq2- rw-r-r-1wjjwjj802011-08-0509:58mq3wjjflpanda-G31M-ES2Ci/Unux3+1/testcode/Posixfbuff=wjj_xyd,read100bytes,priority=1wjjepanda-631M-ES2C;/linuxJ+1/testcode/Posix$buff=wjj_xydfread51bytespriority=1wjj8panda-G31M-ES2C:/linuxi4-1ZtestCode/PosixSbuff=wjj_xyd,read100bytes*priority=IBwjjCp

29、anda-631M-ES2C:/linux3+1/testCode/Poslxfgccmqsend.c-omqsend-Irtgccmqreceice.c-omqreceice-IrtIs-Imqueue./mqcreate/mql./mqsend/mql1001./mqsend/mqj5812./mqsend/ql10018Is-Imqueue./mqreceice/mql./mqreceice/mq2./mqreceiceZmq3intmain(intargc,char*argv)(if(argc!=2)perror(argumenterror!n);mqd=mq_open(argv1,O

30、_RDONLY);mq_getattr(mqd,&attr);/获取属性buff=malloc(attr.mq_msgsize);signal(SIGUSR1,sig_usr1);/接收到 SIGUSR1 信号后,执行 sig_usr1 函数sigev.sigev_notify=SIGEV_SIGNAL;sigev.sigev_signo=SIGUSR1;mq_notify(mqd,&sigev);/注册for(;)(printf(dddddn);sleep(3);/pause();exit(0);staticvoidsig_usr1(intsigno)(ssize_tn;mq

31、_notify(mqd,&sigev);/重新注册n=mq_receive(mqd,buff,attr.mq_msgsize,NULL);printf(SIGUSR1received,read%ldbytes,buff%sn,(long)n,(char*)buff);return;执行顺序为:main 函数会一直往下执行,直到接收到 SIGUSR1 信号,停止当前执行的语句,立刻去执行 sig_usr1 函数,该函数执行完之后又回到 main 函数之前终止的位置继续执行。在 main 函数中些了一个 for 循环,通过 sleep 可以观察其结果。如果在程序执行之前,所指定的消息队列不

32、空,它不会读出该消息队列的消息,即便继续往里写消息它也不会读出消息,知道通过 mqreceive 程序的进程将消息队列的消息读完,消息队列变成空的,再往里面写入消息,mqnotifysigl 程序的进程才能将刚写入的第一条消息读出来。该程序运行时要开两个终端,一个执行./mqnitifusigl,一个执行./mqsend 发送消息,结果如下所示:先在终端 2 往 mq1 中写一条消息:wjjpanda-631M-ES2C:/linuxS+1/testCode/Posix$,/mqsend/mql121wjjpanda-G3IM-ES2C:/linux3+l/testCode/Posix$|然后

33、在终端 1 执行./mqnotifysiglwjjepanda-j31H-ES2C:/linux3+1/testcode/Posix$./mqnotifysigl/mqldddddddddd然后在终端 2 执行./mqsend 再发送一条信息,查看 mqnotifysigl 能否接收到:wjjepanda-G31M-ES2C:/linux3+1/testcode/Posixt./mqsend/mql121wjjfpanda-G31M-ES2C:/linuxi+VtestCode/Posix$./mqsend/mql121wjpanda-G31M-ES2C:/LinuxS+1/testCode/

34、Posixt|在终端 1 查看 mqnotifysigl 是否接收到:wjjCpanda-G31M-ES2C:/linux.34-1/testCode/Posix$,mqnotifysigl/mqldddddddddddddddddddddddddddddddddddddddd可以看出并未接收至 U。然后在终端 2,通过执行./mqreceive 将 mq1 中的消息读完,使消息队列变为空:wjj&panda-G31M-ES2C:/linux34-1/testcode/Posixt./mqsend/mql121wjjepanda-G31IM-E52C:/LinuxS+1ZtestCod

35、e/Posix$./mqsend/mql121wjpanda-G31M-E52C:/linux3+VtestCode/Posixi./mqreceice/mqlbuff=wjj,xyd,read11bytes,priority=1wjj0panda-G31M-ES2C:/linuxS+1/testCode/Posix$./mqreceice/mqlbuff=wjj_xydHread12bytes,priority二1wjjepanda-G31M-ES2C:/linuxJ+1/testCode/Posixt./mqreceice/mqlACwjjpanda-G31M-ES2C:/linux3+1

36、/testCode/Posixt|然后再在终端 2 执行./mqsend 给 mql 发送一条消息(此时该消息队列已经为空了):wjjpanda-G31M-ES2C:/Linux?+1/testCode/Po$ix$./mqsend/mqlvi1wjj(panda-G31M-ES2C/Linux3+1/testCode/Posix$4/mqreceice/mqlbuff=wjj_xyd(read12bytes,priority=1wjjpanda-G31M-ES2C:/linuxS+1/testeode/Posixi./mqreceice/mqlbuff=wjj_xyd,read12bytes,priority=1wjjCpanda-631M-ES2C:/1inux3+1/tes

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论