|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
. r+ x- C' [% F! D( ]. r9 O2 T# l
消息队列可以认为是一个链表。进程(线程)可以往里写消息,也可以从里面取出消息。一个进程可以往某个消息队列里写消息,然后终止,另一个进程随时可以从消息队列里取走这些消息。这里也说明了,消息队列具有随内核的持续性,也就是系统不重启,消息队列永久存在。8 C2 w! i6 H5 C D m a6 t1 v5 L
& |# V4 _0 h% e& O; ?6 Z' @" N
创建(并打开)、关闭、删除一个消息队列! `! ~' W0 @( b/ Y$ H8 `
9 O, d. |4 v* r. C# J5 H ]
1 #include <stdio.h> ) [' y' I" L9 S
2 #include <stdlib.h> % h6 j1 ?2 t) L4 v5 Q' u5 Z% p& m) j
3 #include <mqueue.h> //头文件0 E" x8 C- ?9 e* w
4 #include <sys/types.h> # H0 `+ c* X: {9 d' a( Z B' B& y
5 #include <sys/stat.h>
9 k. n5 n, g1 ?+ y0 ?* ^ 6 #include <unistd.h> % Z2 G" G/ A( v& i0 R; \: e
7 #include <fcntl.h> # |" x$ q/ x5 |1 C3 [7 l
8 #include <errno.h> % `* T" G4 f( G) O3 [. V/ u
9 2 ]- m. \# u( j% @! c9 i# s
10 #define MQ_NAME ("/tmp")
% J9 L1 J2 n( ?" b) d! n11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag
1 Q- B5 b& w! i3 o% \) x12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限 " }, _* E9 v( H1 a4 z/ o
13 ( a/ X+ D; q9 C1 d4 @
14 int main()
8 i9 S P0 f( q, R, g15
: N( P5 x$ q; Y# m0 o) ~- P# D! k) Z16 { , O$ `' L; }$ i" z; t% b1 g
17 mqd_t posixmq;
' R3 V8 X2 n7 D- M8 ~; m6 E18 int rc = 0; % {, F: k! Y: A" X7 ?
19 2 |8 K D# q2 ^4 D8 s3 B
20 /*
: ?! s" ]; B n) L21 函数说明:函数创建或打开一个消息队列
* L+ z0 @- g* k, [3 v6 u% G22 返回值:成功返回消息队列描述符,失败返回-1,错误原因存于errno中 2 P6 B+ G$ p: Y8 N
23 */
% k+ Z* g* f4 K/ {6 K- P4 T24 posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);
: w7 X; B, K( o' ?% d* j25
5 w' w2 @3 b- L n26 if(-1 == posixmq)
7 b+ r& w2 g1 l C2 d) z" X- D27 { @0 e; t3 K2 s
28 perror("创建MQ失败");
% l- Y# e% a+ e7 \29 exit(1); : |/ ~' z: Q2 O; h3 ]
30 } # @& S- w# U+ r8 R8 ^* ?# R
31
9 |6 I4 y2 i: P( Y/ Y32 /* , }' Z% \ |4 |- i! k! x; Z
33 函数说明:关闭一个打开的消息队列,表示本进程不再对该消息队列读写
2 G+ x8 t( F( U# e% O6 o2 y% l5 u6 i34 返回值:成功返回0,失败返回-1,错误原因存于errno中 * S; _6 X3 f+ _! a5 V# N# T
35 */
; G# V$ R* j' B% R" Y' l4 B5 C36 rc = mq_close(posixmq);
) B0 o& f. y3 F37 if(0 != rc)
! e. Q& k/ U& [38 { 7 ^6 e/ H0 v6 u# n
39 perror("关闭失败"); 3 ]3 I" [4 I0 x* d- {# g0 A. f" e
40 exit(1);
! u* {, s$ I* G* u41 } 8 ]" ^0 E. k9 U4 |: h) I0 _
42
: f+ T) A" w% Q2 I% a$ k43 /* # M2 w* s/ w% v+ _$ z8 z2 W9 h
44 函数说明:删除一个消息队列,好比删除一个文件,其他进程再也无法访问
9 J) Z. `0 x. B( u45 返回值:成功返回0,失败返回-1,错误原因存于errno中 9 `9 K1 ~# a& `; g2 X9 q
46 */" l) ~: W) G' H
47 rc = mq_unlink(MQ_NAME);
/ ~3 ?, @7 }- T& \: ~# r; I48 if(0 != rc) - W" s9 Z: q$ _: f8 P" j2 I; F6 N
49 { - [$ I" M) C7 N
50 perror("删除失败");
5 [* ?5 b: f R N# ]51 exit(1); ; U- D, M/ q7 R; Q* i* U3 T
52 } ) L. B' H) L# R
53
3 M; r) y' N. d8 t- ^! i2 t54 return 0;
3 x% S8 i9 b' l c- z55 } 0 G( R; P$ X2 K! o- m5 C: n
" q7 z, [: t/ E& i6 Y) b1 u' [; B G" m8 ^# W0 [0 A# Q
编译并执行:" T7 r/ X& ?- R5 c, G
/ O2 k# j% l4 n" A8 r. l& p 1 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c
8 E8 C: p8 H# G3 f! i- q" R 2 /tmp/ccZ9cTxo.o: In function `main':% u8 ?% k* d: O q
3 crtmq.c:(.text+0x31): undefined reference to `mq_open'
~- f* i9 J1 K% j$ ^ 4 crtmq.c:(.text+0x60): undefined reference to `mq_close'
$ D# H& i- [/ J5 E3 Y! H3 B- p: M 5 crtmq.c:(.text+0x8f): undefined reference to `mq_unlink'
/ N3 m$ E5 i7 Y* I 6 collect2: ld returned 1 exit status, o! t. y) v; d2 y7 q: G, Z
7 因为mq_XXX()函数不是标准库函数,链接时需要指定;库-lrt;
; h- L4 k8 |1 f/ l$ L 8 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c -lrt
+ u9 s" X" y! e. y, v0 C# ~ 9 1 l8 s7 x: @" U% G- N
10 root@linux:/mnt/hgfs/C_libary# ./crtmq5 b0 y0 s, }! D
11 最后程序并没有删除消息队列(消息队列有随内核持续性),如再次执行该程序则会给出错误信息: - u8 d% [9 H! C) M) |4 x
12 root@linux:/mnt/hgfs/C_libary# ./crtmq
: z m8 t( u" C13 创建MQ失败: File exit(0) [8 G. \2 I8 `% H
' w- [* n8 o5 y4 \0 ]
% a7 L$ a$ J! l' b
2 S5 f" K* |: V5 v编译这个程序需要注意几点:. _; k! m5 p: A1 l) n- L
' C2 K: y" v/ ~4 [8 O1、消息队列的名字最好使用“/”打头,并且只有一个“/”的名字。否则可能出现移植性问题;(还需保证在根目录有写权限,为了方便我在root权限下测试)
. I% m0 A) [9 ^4 v+ R2 d8 J* j2、创建成功的消息队列不一定能看到,使用一些方法也可以看到,本文不做介绍;
0 k) o: ^7 B: e6 |% L9 e; @! M8 s# L+ L e
消息队列的名字有如此规定,引用《UNIX网络编程 卷2》的相关描述: mq_open,sem_open,shm_open这三个函数的第一个参数是
- B! u' _5 B+ e" W+ A一个IPC名字,它可能是某个文件系统中的一个真正存在的路径名,也可能不是。Posix.1是这样描述Posix IPC名字的。
0 {( s. Q3 x# ] O8 L; w9 o1)它必须符合已有的路径名规则(最多由PATH_MAX个字节构成,包括结尾的空字节)
+ x n, T) m, C, i! B2)如果它以斜杠开头,那么对这些函数的不同调用将访问同一个队列,否则效果取决于实现(也就是效果没有标准化)
9 W2 q/ B* S* q7 o) ?; o. `, W- u, T3)名字中的额外的斜杠符的解释由实现定义(同样是没有标准化) 因此,为便于移植起见,Posix IPC名字必须以一个斜杠打头,并且不能再包含任何其他斜杠符。0 A: b8 w0 ]* g1 i! u4 Q
7 [% A6 T3 F4 u: l/ y: w- A
4 y2 u$ D* c1 R! m$ BIPC通信:Posix消息队列读,写+ |9 N: r' M, W* D5 D, @
1 E! x* Z+ L! _0 c
创建消息队列的程序:5 c) p, U& u7 I; B2 q
% O( v; Q- ?7 y0 A" D. v
1 #include <stdio.h> & k2 @* b' i) [, L
2 #include <stdlib.h>
6 ^" P4 { v: J& u0 ?8 p 3 #include <mqueue.h> //头文件' Y5 I" p$ w6 m$ O# j- O6 B
4 #include <sys/types.h> ; V) h# ^: c& ^* [' v) z7 {& o8 G4 j& m
5 #include <sys/stat.h>
/ ?, E5 @3 i- d+ H 6 #include <unistd.h> , j0 {9 b/ w* O
7 #include <fcntl.h> 5 H4 N7 F' c6 n6 F' Q6 B" y4 q
8 #include <errno.h> * u3 }* t8 Y K! Q
9 - x; u" ? Q# O; w. { C2 i
10 #define MQ_NAME ("/tmp")
9 E& Q' V1 q/ U, l# S# w11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag
. B' n* O( c1 `) l+ }6 e! G12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限
0 l6 t9 `% S4 o! d. X) f13
8 u+ v+ E& T) y' a: s5 N7 H14 int main() $ z" z6 b; @( T
15
# n3 f" w; q8 @2 s% `16 {
0 b8 h' Q* O* s. ^, j) ?17 mqd_t posixmq;
6 f1 e8 t' C: t( C3 R18 int rc = 0;
; l3 M6 m" x0 `( B% C" X7 @8 p- I19
4 I! l* m- p& t) F20 /*
6 v" w# P! T) E) {8 G21 函数说明:函数创建或打开一个消息队列
8 P% r |( V! c5 u r22 返回值:成功返回消息队列描述符,失败返回-1,错误原因存于errno中
" M, D$ D, D# |# R2 f23 */
% F& k! I6 u) K' H24 posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);
) m$ K; _2 q( ]; G25
: `+ }+ I6 y1 O* r$ J+ {26 if(-1 == posixmq) 2 ^. F" c+ A- D0 q c3 E! E) o0 s
27 { 1 c- r P; `( Q4 e. k
28 perror("创建MQ失败"); l( E7 {( k$ e
29 exit(1); ; I) H2 W( ^0 t% v: q' ^; A7 B
30 } 0 a% Y3 o1 v' ?
31 % v& {. ~" v: \7 _
32 /*
; n* G$ y7 M, v% y7 s2 m33 函数说明:关闭一个打开的消息队列,表示本进程不再对该消息队列读写 3 _, u3 P$ C% C5 z7 @
34 返回值:成功返回0,失败返回-1,错误原因存于errno中 6 I5 J- v( U# q( H( T! T
35 */
5 }& `* L' P$ W* Y36 rc = mq_close(posixmq);
0 ]) V O1 M& t37 if(0 != rc) 3 L W0 m) W8 q9 r8 k
38 { ! y0 F |% c) x
39 perror("关闭失败"); " R( e, L* K E" K3 x5 N# h/ J$ _2 n
40 exit(1);
- t% r7 @7 s, x1 P) v/ L+ n4 P41 }
8 f& k/ @& f( l c5 G0 X% g42
3 M5 Z. S+ |3 x4 u" `, Q43 #if 0
# J% {& T" f' }# n$ R! C5 A44 /* + A5 N1 L+ b% W1 ?. Y; }* @
45 函数说明:删除一个消息队列,好比删除一个文件,其他进程再也无法访问 # }& z3 j5 L& b/ m" [
46 返回值:成功返回0,失败返回-1,错误原因存于errno中 / n/ F: { d4 j! f( b( A. V" _1 o) Y
47 */
9 @7 R# X2 F; i; r9 T: P0 M% h48 rc = mq_unlink(MQ_NAME);
% K/ t& x" l4 M O0 M8 e49 if(0 != rc)
" j" ^" S/ e8 W50 {
4 \3 ~4 z1 X( F& b9 c51 perror("删除失败");
8 }- t% C8 M+ b' Y, D52 exit(1);
* y0 t! P, a6 x4 t, E4 E/ a53 } - e: b3 j, I, |# F% [
54 , m/ I0 T" M* V: y
55 return 0;
5 d2 v4 t ^3 ?6 k+ A1 l56 #endif
* D& k" i) I5 d' t1 g' y' [4 d57 }
; p+ V# }( Z+ v" q, r$ J" w4 {% R k, v' ?# j; R* J
' m, z" b; G9 ]1 I: F) d# O' u* p" ` J4 u# }, ~
编译并执行:" S. m2 a. D! _+ A M# v5 u2 P
8 \7 f4 C5 D. s; N$ @( c8 T
1 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c -lrt- H/ f1 `/ u3 Y' v3 j3 y
2 root@linux:/mnt/hgfs/C_libary# ./crtmq
9 z0 I# f& P# S4 C! x9 d3 程序并没有删除消息队列(消息队列有随内核持续性),如再次执行该程序则会给出错误信息:
; J2 t% B9 a% G% ]) H4 root@linux:/mnt/hgfs/C_libary# ./crtmq + I, z ^& O' _ R9 q) H- p: e
5 创建MQ失败: File exit(0)) e! R/ i4 t. M
4 ?! o+ w. U9 k
0 d2 B4 h8 I& R7 p; y$ B向消息队列写消息的程序:0 m! t9 b* N8 U& U+ J5 ~5 K; e8 ^
4 q: m6 n0 K, ] J- 消息队列的读写主要使用下面两个函数:
- /*头文件*/
- #include <mqueue.h>
- /*返回:若成功则为消息中字节数,若出错则为-1 */
- int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio);
- /*返回:若成功则为0, 若出错则为-1*/
- ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio);
- /*消息队列属性结构体*/
- struct mq_attr {
- long mq_flags; /* Flags: 0 or O_NONBLOCK */
- long mq_maxmsg; /* Max. # of messages on queue */
- long mq_msgsize; /* Max. message size (bytes) */
- long mq_curmsgs; /* # of messages currently in queue */
- };& X3 v$ e. D: \* c. l# \4 p# R/ s1 \
1 f( U+ m; W0 L* I2 a! C1 L" k O
) G7 `" M- i2 [4 z$ {7 Y# m" _: j: P4 [! y
L3 Z9 t5 x: l: {% H# ~4 r2 h
# r4 n2 [6 u L p$ n 1 #include <stdio.h>
$ x7 ]/ d% R' z- C4 _: N 2 #include <stdlib.h> - l" b0 t! a- B Y4 p0 X
3 #include <mqueue.h> & b: N% C, f/ ?# ^4 y% g& e _
4 #include <sys/types.h> : I6 T5 q2 k' b0 c
5 #include <sys/stat.h> ! K# p9 R* V& n1 |; E
6 #include <unistd.h>
7 C+ R/ r0 e) e6 D. N 7 #include <fcntl.h> - n% T1 c& Z5 y, p
8 #include <errno.h>
+ |8 _0 |' P. j7 ]& |' |* F5 O 9
. K9 |) J; E4 c6 H10 /*向消息队列发送消息,消息队列名及发送的信息通过参数传递*/
0 a8 K- R% D; E1 |; o11 int main(int argc, char *argv[]) , s! e6 W8 h8 z/ _0 m/ y! C7 i
12 {
7 _7 ]+ ? ]) y( f9 P13 mqd_t mqd; / N1 T* ?9 @1 f- v0 B9 A
14 char *ptr; ; m* S; i/ k, ^) o3 z2 {# H3 ?
15 size_t len; ; z2 q7 |( `6 g# X
16 unsigned int prio; 6 c) Z6 J. J0 q$ F
17 int rc;
. |2 Q, J5 Z" c, u: i# L18
+ e7 @+ c+ Z, B* E: f. N19 if(argc != 4)
; [' u, \! X) a6 ]$ l# J2 [' a20 {
: h B6 [# g7 {* u {21 printf("Usage: sendmq <name> <bytes> <priority>\n"); ( |% J& b1 S |+ J1 u, ~
22 exit(1); ( C' Z1 _( |3 @2 J# `/ S- Y
23 }
, E: { W; f" u9 A) Z" `# @24
7 D. v5 n/ A( \+ m! t$ ^4 |" \25 len = atoi(argv[2]);
1 R+ ]& ^0 `7 f% o" J26 prio = atoi(argv[3]);
; @% f! {' I" |) R$ L, R. I27
Z+ e0 u7 d8 m; D! ~28 //只写模式找开消息队列 7 J* t* G7 E, ^' B; B- l& [
29 mqd = mq_open(argv[1], O_WRONLY);
! V2 l# J5 V" }' e% V% ^30 if(-1 == mqd) : a# Q3 k0 k6 c4 u" G7 k) q
31 {
) _1 H. N u3 Q" k7 `6 s32 perror("打开消息队列失败"); " }" U9 _% `. i! i% r l
33 exit(1); , W/ {% i) K: W" v1 E
34 }
+ N! g6 N; {$ N% m: y* w35 ( C5 `- j, p! E, x! a* G
36 // 动态申请一块内存
% ~1 t$ H/ u" n& z0 z+ a+ e37 ptr = (char *) calloc(len, sizeof(char));
5 D( C% K0 U3 u6 \" y' ~5 C38 if(NULL == ptr) 4 c4 K# Y! N& P4 P, G1 `
39 { 3 L0 z% r9 P* _
40 perror("申请内存失败"); 4 j# U9 j( ^" V8 o! K# v
41 mq_close(mqd);
. u! Q9 c0 k; p$ o$ C42 exit(1);
Y4 c3 ~& i4 @3 M1 b43 } - b0 ^& D( W) K* P# K
44
3 q+ H- f8 M; e4 ]6 [1 S45 /*向消息队列写入消息,如消息队列满则阻塞,直到消息队列有空闲时再写入*/
- Y' l1 A) |0 W+ ^4 ]9 f46 rc = mq_send(mqd, ptr, len, prio);
7 K5 ~; G# M% r# W47 if(rc < 0) ( y q( k9 ~: R7 j: P8 c
48 { 1 R v5 b6 ]( ~
49 perror("写入消息队列失败");
- H# @6 J0 ~8 a4 D# F' M50 mq_close(mqd);
$ a3 y! v1 x, t& {51 exit(1); s: F. ? G3 j0 _ z5 S' _4 P
52 } # E# k' r& ^* f$ l
53 & _4 n! K, x0 u' \
54 // 释放内存
3 |( w8 v, p, G8 H0 B5 t" h& h, ^( j55 free(ptr);
v' w% l- h) @$ F56 return 0;
7 E3 n) \) A% [' e$ g) e5 l9 L" i57 }
5 v; b8 Q! O& Z+ `* _; a* l
9 q& V7 ?8 p) ~+ J2 S I" |, Y) j( Y5 b0 P/ a% K" u( o
编译并执行:
5 v' ^" @2 b# R7 U
$ d, t: F, Y: E2 ~6 l1 p1 root@linux:/mnt/hgfs/C_libary# gcc -o sendmq sendmq.c -lrt3 d7 K" T$ I# b1 V
2 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 15
' q0 o9 D3 Y9 q3 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 16- ]3 o4 c. L* Z* M
4 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 17; `$ f* q8 @0 y4 d ?7 t8 l
5 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 189 g1 R5 a( X$ e6 N; C
' [0 p$ E9 m* r6 }
上面先后向消息队列“/tmp”写入了四条消息,因为先前创建的消息队列只允许存放3条消息,本次第四次写入时程序会阻塞。直到有另外进程从消息队列取走消息后本次写入才成功返回。9 T& V$ [0 P' i- k* {
! W( k6 s) K0 i# V$ h! {) K3 n$ R
0 w7 E4 k" o+ \4 P7 j
+ c# X9 j) c2 G1 s* [$ s读消息队列:
3 ~# z* [! L u5 Y( A& E
3 G+ B" @8 l4 M, D" ~0 ? @#include <stdio.h>
+ A& `7 T# f4 O4 L; A: E9 n& y1 |#include <stdlib.h>
' P+ _+ b* U4 e) p( r- ~#include <mqueue.h>
( d2 X2 r) `; I* T% f8 c#include <sys/types.h>
k2 R0 i! R' b9 @. y#include <sys/stat.h>
$ h( k2 C- C6 F, y4 P2 D#include <unistd.h>
0 b9 a- f7 R8 G) C# v( v#include <fcntl.h>
- k( s, o+ l+ T#include <errno.h>
, v. ]. u. n3 M. A3 f* m S
: k2 B% ~; E, s* w% L/*读取某消息队列,消息队列名通过参数传递*/ 0 Y" s t% L" q# E
int main(int argc, char *argv[])
# w& \+ X' `9 u0 {{ % U3 j; n4 y9 |3 q9 }" v7 O
mqd_t mqd;
0 r; o2 Y: w) ~1 T struct mq_attr attr;
+ O% Q7 D- I/ u) L* R5 [0 G' F char *ptr;
- c5 _4 U0 T* S8 o! u } unsigned int prio;
: V' }) B6 \7 E! `; e, _ size_t n;
+ F2 c" K$ V: q+ \ int rc; 8 ^# m7 ^, w3 n7 _) _8 B
( G$ A! h* w! d Z0 s6 { if(argc != 2)
$ \ F! ^4 O9 g3 v {
7 S% y- Q3 M! o+ a) z& `) ^ printf("Usage: readmq <name>\n"); $ @9 |! C1 h+ [8 [
exit(1);
- r. u9 h) x( ~) I9 v- O* L } " |7 N" |: J, ?6 O2 I2 V5 ^& L" ?
. k* N' [5 I; I& M6 Y, I
/*只读模式打开消息队列*/
. s: y2 J# L/ s mqd = mq_open(argv[1], O_RDONLY); ) Z; ?9 N1 G8 l, A4 P* B
if(mqd < 0) " |9 \) {& G: R3 K% C4 j) N
{
9 L/ `7 l" V/ c9 s6 T, ?7 v2 d2 ^ perror("打开消息队列失败"); 6 M F4 k5 O5 N3 r% r# j* u4 q
exit(1);
( Q9 _3 b o4 R' q }
) g3 Y% m& L" c" @
6 X' t/ K- a* q) ]: o // 取得消息队列属性,根据mq_msgsize动态申请内存 : ] y% J- v% l1 t- F
rc = mq_getattr(mqd, &attr); % h* Q1 f7 J& G7 P7 s* ^
if(rc < 0) . B2 E. N( y7 h" c
{ * v9 w6 s& a5 s+ q$ _7 R. K
perror("取得消息队列属性失败");
1 o! c/ \4 Z5 @2 F" O exit(1);
* P! k7 y1 ] L5 H9 Y } ) F& G' Y8 ]: Y* y. V y$ E, O
5 u, O& E# K, _) d5 H
/*动态申请保证能存放单条消息的内存*/
/ ?& K& ]3 j+ ]8 P ptr = calloc(attr.mq_msgsize, sizeof(char)); 8 I4 f; }( @! z0 H0 ~5 k7 Z. M
if(NULL == ptr)
! O e8 \ m7 m8 B' c, K9 m {
% J, l+ l0 t1 o printf("动态申请内存失败\n"); 2 d; E& e) ? c% A4 i
mq_close(mqd); 9 Q& X- U; |3 w0 x: ?/ }
exit(1); . n( I: A) g; O% [- A1 s
} ; H4 f- H/ ~/ ]& s/ n# ^; [0 t
8 o" F* ^" F2 l# w0 K. o
/*接收一条消息*/ % k. w. x% D4 `$ s) `1 Z
n = mq_receive(mqd, ptr, attr.mq_msgsize, &prio); ! b% w/ K3 X* A9 F8 B1 n0 C Z: @. H
if(n < 0) ( ? v+ V+ V# b8 [# r
{ 9 j3 N- ?5 K7 P; \) d' ?! g
perror("读取失败"); ' [& L* q# c7 M' c" u
mq_close(mqd); 7 S# S) g) R! D8 b! ?- w& A2 ~
free(ptr); 8 |& T' O1 q0 {' T: O2 f5 u
exit(1); " v) X6 p$ K. C* C
}
7 m5 A2 r+ l% n( S3 W H: P% ^8 @5 g2 d! ^
printf("读取 %ld 字节\n 优先级为 %u\n", (long)n, prio); 0 i) y' c8 m7 r, n, \: x6 ~4 z+ i
return 0; , y1 P% p1 k7 S: Q6 y+ h
}
& t! u2 r& d1 b8 }, p' l2 D" I! e1 T" N
9 \) D2 Y% G6 X& m* m; L v
, J- K3 {' ]1 t2 y编译并执行:- a* y/ j; x2 j, E: X
) W* J1 e9 H1 v/ M 1 root@linux:/mnt/hgfs/C_libary# vi readmq.c
. A2 ]+ i& |! O d8 I! k! A 2 root@linux:/mnt/hgfs/C_libary# vi readmq.c
8 P1 A8 }( d" @9 o( o 3 root@linux:/mnt/hgfs/C_libary# gcc -o readmq readmq.c -lrt
# j1 r- c* u4 r7 s, G9 N 4 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp0 C% b0 f1 H4 s. e8 h( @: _% ?
5 读取 30 字节
0 N: W7 x, s# E. \ 6 优先级为 18
. R5 L" h$ w. m, L" V 7 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
7 I9 N1 t& u/ s 8 读取 30 字节% c# }: ?9 n( V6 Z7 x0 ~* U
9 优先级为 17$ I( e; j, k# M5 J" @
10 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
5 @0 f0 p( M' b; n11 读取 30 字节9 \' B, d3 o4 a; [& W0 C
12 优先级为 16
$ a7 `. X, K7 x13 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp. v# G, C7 g1 R& Z
14 读取 30 字节
, {2 \! k6 u5 y* r( a15 优先级为 153 x0 U5 Q' i$ y, T q. G+ N
16 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
! _+ g5 {/ U; C+ Z o( ^, f. j, m! Q+ H$ U
; @1 \0 m9 o% q2 y
Q: \! `8 R& u& z6 q9 I2 G5 C
程序执行五次,第一次执行完,先前阻塞在写处的程序成功返回。第五次执行,因为消息队列已经为空,程序阻塞。直到另外的进程向消息队列写入一条消息。另外,还可以看出Posix消息队列每次读出的都是消息队列中优先级最高的消息。5 V8 a! I. ?7 i8 S+ s0 U0 b4 e
/ n7 _3 I4 n- U, b4 O
/ N9 d, T g0 D# A4 j7 P
7 l" M) h7 s* M- NIPC通信:Posix消息队列的属性设置
# M, j, x! N5 r6 ~- A1 e* U
$ Z. a: y3 ?: L% m+ d/ p. j0 T+ }- Posix消息队列的属性使用如下结构存放:
- struct mq_attr
- {
- long mq_flags; /*阻塞标志位,0为非阻塞(O_NONBLOCK)*/
- long mq_maxmsg; /*队列所允许的最大消息条数*/
- long mq_msgsize; /*每条消息的最大字节数*/
- long mq_curmsgs; /*队列当前的消息条数*/
- };
- 队列可以在创建时由mq_open()函数的第四个参数指定mq_maxmsg,mq_msgsize。 如创建时没有指定则使用默认值,一旦创建,则不可再改变。
- 队列可以在创建后由mq_setattr()函数设置mq_flags
- #include <mqueue.h>
- /*取得消息队列属性,放到mqstat地fh*/
- int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat);
- /*设置消息队列属性,设置值由mqstat提供,原先值写入omqstat*/
- int mq_setattr(mqd_t mqdes, const struct mq_attr *mqstat, struct mq_attr *omqstat);
- 均返回:若成功则为0,若出错为-1
2 q3 {' b; Y7 ]0 q0 E 0 ]2 i0 J9 S2 ~
" z& I+ b- p8 o! ^- }) n( O
程序获取和设置消息队列的默认属性:
- z3 d, C% Z) }5 r/ E [
* C8 M9 ?5 y9 j) b 1 #include <stdio.h> : U) w+ L5 ]/ f/ a( y
2 #include <stdlib.h>
; v) b1 z" ~4 X3 F$ P7 o: r/ X3 b. [ 3 #include <mqueue.h>
9 L$ a7 ^. H- n6 E. w+ ] 4 #include <sys/types.h>
# M* P# m8 D3 N7 N4 T$ X7 [ 5 #include <sys/stat.h> : V1 C' r8 ]' z3 q
6 #include <unistd.h>
) C" y$ _+ ~$ [ 7 #include <fcntl.h>
, N2 X9 u/ r2 e, y @ 8 #include <errno.h> ; B+ T8 W! w' o, z6 q
9
: Q' u2 B Y( l10 #define MQ_NAME ("/tmp") # G) q0 f( k; ^( m3 O# x
11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag
1 V B9 ]" s4 P) [7 j/ Q( @8 S7 x12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限
9 T$ H! P4 U. B; x* x13 ' y( R/ t& o( v) ` C) \
14 int main()
/ |' v$ U9 u% I6 x6 m! V15 { 3 a+ S+ j- }( `! I- q# ?7 [+ ^
16 mqd_t posixmq;
4 B& X1 A4 Y8 s3 n" d17 int rc = 0; ! z) _5 F+ ^+ ?8 n4 U
18 i2 e' | u0 J( D' Z4 D1 S
19 struct mq_attr mqattr; $ M5 L- I1 Q, q$ @ |5 R2 `
20 T% t7 p( Y* \ }$ ^
21 // 创建默认属性的消息队列 8 X9 ?2 K; x% i# J% d7 ^" m
22 posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);
6 f, p$ r) u' l* d& M( P9 E4 a* e23 if(-1 == posixmq)
" e3 J9 b1 B y/ D24 { ' f+ I9 P6 W8 H B" r& T. \2 F* n
25 perror("创建MQ失败");
6 f. K4 o" ]% m& u26 exit(1); + t$ \/ G' ?6 H- D' H
27 } + t1 r( `8 Q7 w% j% \# L
28 D% n& ~; k) S' T5 q0 U" U
29 // 获取消息队列的默认属性
) w1 C6 C4 R1 ~5 M% e9 M* r6 @3 H30 rc = mq_getattr(posixmq, &mqattr); # L* Z" r& W ]1 M' S! V+ R% y
31 if(-1 == rc)
6 C8 f6 U( Y$ S$ I32 { 2 Z. t7 j2 k" t2 F4 S
33 perror("获取消息队列属性失败");
' V- V5 c( W( X; Q1 C34 exit(1);
( ^" A8 `: b; x; L& ]' v35 } 2 B+ N8 O1 R6 @& I/ L& e7 R
36
' \0 }$ q) R2 I/ K; E4 i- W37 printf("队列阻塞标志位:%ld\n", mqattr.mq_flags); 0 B$ Q8 t- n8 A+ }5 W) @/ m* N
38 printf("队列允许最大消息数:%ld\n", mqattr.mq_maxmsg); ! C- N$ @$ |1 m: q& L
39 printf("队列消息最大字节数:%ld\n", mqattr.mq_msgsize); ) e U& _' j/ M3 o8 K1 Q
40 printf("队列当前消息条数:%ld\n", mqattr.mq_curmsgs); # X6 w/ E! K* Q1 M+ @! M: E7 X6 H3 e
41 0 c4 A l6 ^( j) ~4 G: `$ t
42 rc = mq_close(posixmq); 7 B2 T% T" ?' w: Q, ~+ Q* I, W
43 if(0 != rc)
, a: h1 [5 b: k' X: H+ u44 { 9 M4 K7 \# T- V9 M6 X1 z
45 perror("关闭失败");
$ x8 ^1 E% X( U4 v. v/ e* k46 exit(1); 3 Z+ d9 n0 O1 ]. o5 Y
47 }
; [; O: |" a4 {# G0 C4 q5 ]5 [4 i48 - m0 m7 V6 @$ _) F! E6 S
49 rc = mq_unlink(MQ_NAME); ) E! I% c5 [& z- v3 ]' ~
50 if(0 != rc)
1 E) q1 A4 x( u51 {
4 q! N/ z. l( N! R1 V52 perror("删除失败"); # b% R- s# F+ }
53 exit(1);
& a! y1 o; F+ ? W* h54 }
: P" w: L; m8 D" B) Q; q& B55 return 0; 8 X- ]# v: i# O5 A- k8 n9 p! ~( w
56 }
- Q& s8 Z1 h; W, `) `2 B& }/ `- g4 ]# j/ ^7 ^% A7 g
- H/ ~3 P4 _1 j: ?; l H8 U+ R
编译并执行:) K6 @$ \! j# w' P2 `" n
. a4 l; K9 X5 X
1 root@linux:/mnt/hgfs/C_libary# gcc -o attrmq attrmq.c -lrt1 l. u: h( X/ {. W& i2 s' K3 q" c/ F
2 root@linux:/mnt/hgfs/C_libary# ./attrmq# S9 Z' s9 T, d1 A/ b
3 队列阻塞标志位:00 A: A$ U0 T1 e' ]8 i. z
4 队列允许最大消息数:10# e$ V1 e5 t* G3 }% I2 `# u
5 队列消息最大字节数:8192
7 r# n/ T2 S7 ^9 W3 _. i. z6 队列当前消息条数:0! J! V% g1 Z( f
7 root@linux:/mnt/hgfs/C_libary# 0 B9 M+ J/ l/ {+ h. Z& t' j
* e* `2 b( s+ [
* F: X$ I0 a+ e: ]4 \设置消息队列的属性:
1 z: q8 C2 G' e+ q5 H' B( N+ P1 O3 x' B: N! C4 \; N. b- [$ E/ p1 M$ y0 B
1 #include <stdio.h>
2 t$ m4 {" [) @ 2 #include <stdlib.h>
( ]! Z; X* g4 t* A% | 3 #include <mqueue.h> 5 B0 D& J1 b. {
4 #include <sys/types.h> * g! M9 V1 j( C0 g5 _) f
5 #include <sys/stat.h> ! S& g9 u4 y6 G {, x
6 #include <unistd.h>
- H5 G% u7 [2 b/ D$ P4 K 7 #include <fcntl.h> o8 M, d; N8 ~* P1 s/ K
8 #include <errno.h> - |: f: a; s! T: T% Y$ f2 d
9 0 @6 i" Y$ h4 @1 u$ c% P1 L" `( b
10 #define MQ_NAME ("/tmp")
- M+ S2 m) N8 X. x, r11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag
1 T* n8 s5 `9 s8 W. {12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限 * A* y" W+ p E# d
13 & E7 }8 H) d$ c( M& L
14 int main() ' Q. h# S$ p+ X
15 {
- u% V$ w" j3 g16 mqd_t posixmq; # a. F; P1 {$ \8 Y" [2 z% ?
17 int rc = 0;
+ o: d; f' g/ X! M I0 ?8 s$ V Z18 - R/ Z3 N! F5 y* n, Z, z% i
19 struct mq_attr mqattr; * c. x4 ?" j1 v: T
20
# y' b3 g; ~. ^. W- N# S21 // 创建默认属性的消息队列
' d" K* M* b( P5 d& w22 mqattr.mq_maxmsg = 5; // 注意不能超过系统最大限制 6 V# D* ]& s& k" L [9 S
23 mqattr.mq_msgsize = 8192;
: \0 X$ ?. g( _24 //posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);
# h+ f# U3 U. g, R4 h/ J0 k25 posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, &mqattr); 1 `/ \ U5 _; o" F4 j M
26 3 k' f6 b) I$ u) c* Z
27 if(-1 == posixmq) / ?$ a, f0 ?) U+ ], Z; T
28 {
6 j# C# Y& Z+ u& X K# u5 O29 perror("创建MQ失败");
1 e/ n8 x) s9 }+ z: G) M5 r30 exit(1);
; T) g, o- {0 k6 D) H2 i% {' ^) M0 a31 }
3 w, E) q- C3 S2 N' n32
) P' C3 c5 a. B/ u: r' ]) T33 mqattr.mq_flags = 0;
+ |( C$ Z$ ] N% N# Z34 mq_setattr(posixmq, &mqattr, NULL);// mq_setattr()只关注mq_flags,adw
/ }9 ^) V& l% n! k* P& V8 l35
: Q9 W5 v! j2 f0 M" y6 M36 // 获取消息队列的属性 ( m" U1 {( ^# i3 m% f) i V6 ~1 o
37 rc = mq_getattr(posixmq, &mqattr);
5 l$ C* z0 j+ T& O2 L38 if(-1 == rc) 5 e9 C. g$ p5 C: _
39 {
I! K( Y5 T* [. p5 k+ J3 \$ z9 |) j40 perror("获取消息队列属性失败");
( Z: O8 F" b) [3 M4 d8 Q1 b41 exit(1);
- b8 \7 ~$ p) I9 G3 e/ l42 }
: |( Y% M# b g! ^* D43 5 {, e1 e3 z# V) q# _: p+ ^8 n k6 w% Y/ i
44 printf("队列阻塞标志位:%ld\n", mqattr.mq_flags); " Q9 a7 T/ T9 y( c6 R
45 printf("队列允许最大消息数:%ld\n", mqattr.mq_maxmsg); : y! }9 Z8 B( b% J3 M% n
46 printf("队列消息最大字节数:%ld\n", mqattr.mq_msgsize); 9 ^$ [& h: c- j3 P% v
47 printf("队列当前消息条数:%ld\n", mqattr.mq_curmsgs);
) \1 m3 R% u+ W" O6 g48 ! ]8 Z* [& k9 ~4 Y( W% F
49 rc = mq_close(posixmq);
4 r# a( q: e6 l3 b3 r$ v( \! ~50 if(0 != rc)
4 ?$ ^5 ^4 v9 h# w51 { # d: U" i; L" d: C6 v9 y x
52 perror("关闭失败"); 9 c3 Z3 K- A$ G% U! j) Z+ K
53 exit(1);
$ b) ~5 q& F8 B0 v54 }
$ I6 W$ G. v( w; k, K" N/ j3 a! E55 9 x" E7 U' b! M; }9 Y
56 rc = mq_unlink(MQ_NAME);
g0 n' M- D# k/ e! E: w6 T- P57 if(0 != rc) 2 B2 r$ T$ ]7 b! H
58 { ( m8 O: k, Q+ x
59 perror("删除失败");
5 i& ]: K, P A4 p; I6 V5 v v, [60 exit(1); * \" n( s2 W: `9 ?! b5 D* R4 {
61 }
5 w ]5 N4 w9 d8 R' M62
, Y6 o3 x, i; h1 d+ H: V$ f0 v63 return 0; & ~1 B+ [" p) Q* x6 v1 F
64 } 7 W& y! m5 }% {, l+ S
0 B6 P. a: e, c3 [6 \- {1 p8 ~6 D
: b3 [8 D8 o9 k1 J4 ^' K/ w编译运行:
! p1 D) ~5 D# k: V: B3 O$ a, t# C; o# r4 r
1 root@linux:/mnt/hgfs/C_libary# gcc -o setattrmq setattrmq.c -lrt( G/ l; q2 ~2 L' L- W( i$ i
2 root@linux:/mnt/hgfs/C_libary# ./setattrmq
# k. L- L; K2 C3 b3 队列阻塞标志位:0
( X, z2 G, h4 |# U7 g: h4 队列允许最大消息数:5: t- u3 t; f/ Q+ z
5 队列消息最大字节数:81924 d5 K* T T3 Z6 E) ]: C, _
6 队列当前消息条数:0$ g/ s) X% R( [9 L
' d5 j; @: S/ @* D
^8 B4 y$ _# b# w1 |& c, y% c: D' O: p7 ^: H/ n' F4 v
, t* U/ u P3 C" r9 C/ e, b! M+ J: d
. z' h1 w2 |( T+ h* y# O+ S
6 d/ c# B. H" s1 W( i4 {# ]5 y: u/ {: M. |" p
( b# f) ~0 f* d$ `. r( e/ o. [" r4 m- U
- P9 W: B: p+ R- V. Q* Z
|
|