|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
# Q! \) e5 F" b; @/ b5 u5 D* K 消息队列可以认为是一个链表。进程(线程)可以往里写消息,也可以从里面取出消息。一个进程可以往某个消息队列里写消息,然后终止,另一个进程随时可以从消息队列里取走这些消息。这里也说明了,消息队列具有随内核的持续性,也就是系统不重启,消息队列永久存在。
4 J8 R' D( B8 a& O, `
5 L, X0 }7 p3 K, K创建(并打开)、关闭、删除一个消息队列
7 \6 q# N# E6 f. |$ ?; J
1 k( i* w9 `! Q- |7 U 1 #include <stdio.h> 9 t4 x# k" Y9 r3 x! m' I
2 #include <stdlib.h>
& t$ U( [9 S% W7 H3 [+ O 3 #include <mqueue.h> //头文件. }# }! J1 G5 ^: a5 l0 }9 l
4 #include <sys/types.h> 3 ]7 o" Q# ?8 x4 B% } d
5 #include <sys/stat.h> % ] @& l: ]) Q( M A6 t B
6 #include <unistd.h>
5 ?( E: c/ G/ w7 J. h0 D/ d9 ~% J 7 #include <fcntl.h>
& Z& N% \; l" n- t5 p, W) Q7 d2 i 8 #include <errno.h>
0 q- H6 R; \ Z9 q0 b 9
6 c' {1 _* p$ q: N% s$ e; T10 #define MQ_NAME ("/tmp") 5 p) ?" h+ h |$ |+ z+ y% p
11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag
" g8 m- C, X/ P( O, m3 T: n' r12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限 - V I$ A8 [( Y# l8 {
13 ' M/ T4 h( \7 ^# {
14 int main()
" j1 g( C+ g4 G15
+ k, e3 P k6 R3 a9 h- {7 j16 {
; v) {+ N6 J! ^) ~8 U( `17 mqd_t posixmq;
4 h% I# j/ {2 w18 int rc = 0;
0 {1 |% S. R5 u1 G$ m8 s* k+ H19 7 ^) p9 R8 W% M% j
20 /*
0 g) T0 s3 g1 Z" g21 函数说明:函数创建或打开一个消息队列 & S/ t2 w- N8 _- i9 E4 X
22 返回值:成功返回消息队列描述符,失败返回-1,错误原因存于errno中
% I$ ], _( m" l+ F3 }3 Z23 */
% ^; N# O+ Q! f" ?. `# B7 {- y24 posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);
3 x6 P/ j- s& s) p7 T: ?/ R25 8 B% f4 @0 q0 |6 F& ^0 U& w/ z t
26 if(-1 == posixmq) \& Z" q1 i5 D( K: ^
27 { 9 O7 F2 H- g. K$ z
28 perror("创建MQ失败");
- h& P( M4 i, ]. I/ T* I4 D$ R% ]29 exit(1);
. y- v' F, b0 l" g0 B" _. R. B. m30 }
, j0 l! X7 e; @0 E7 T1 o31
: `/ b S1 @ a# _1 H4 x" K2 n32 /*
7 l4 C. V% A& n33 函数说明:关闭一个打开的消息队列,表示本进程不再对该消息队列读写 , H% D. y# J. _7 P# ]# F K. g
34 返回值:成功返回0,失败返回-1,错误原因存于errno中 * E( ~: h! e2 @' d8 j
35 */
1 J- }% p; R0 ~( ?2 y36 rc = mq_close(posixmq);
n- X0 {6 X* U% r37 if(0 != rc)
! [- ^/ `9 x- w) K38 {
* E# z; a Y$ i1 E, i39 perror("关闭失败");
7 x3 I7 ^! F! R M40 exit(1); & U' W0 l5 o7 n3 n5 g
41 } & h5 |0 ^/ G$ l
42 4 W: p R. Q! M$ v) F; n- N2 v
43 /*
8 e: o4 j9 t* e8 M9 Y7 L44 函数说明:删除一个消息队列,好比删除一个文件,其他进程再也无法访问
( t# W2 w5 K9 q$ i. O9 l, a45 返回值:成功返回0,失败返回-1,错误原因存于errno中 6 a! V3 O4 ~3 T3 q3 G
46 */& W, {6 I: p% a- P: t
47 rc = mq_unlink(MQ_NAME); & N5 k# n) Q& F$ N6 c# c. U
48 if(0 != rc) 7 @# x# B3 X% O. t
49 { , g @7 H# v _$ a% Z
50 perror("删除失败"); 7 _5 N6 N& E! _% d) ?% b
51 exit(1);
5 W6 }7 F- B' R52 } 1 v- ^1 L; `3 W: B, c
53
9 u- J5 e+ H# ~5 m" I54 return 0;
: V, _6 d& y, |% Z. n" H. F55 } : w( L! k% N3 E! p% _9 E4 T
5 C# u: T! E v4 i5 f* n6 F: m L
7 x! y3 t$ v* m, g# y
编译并执行:
3 C6 _6 L, w9 M/ r
; d4 B4 v& w7 f* O 1 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c
6 o) t E- X# m 2 /tmp/ccZ9cTxo.o: In function `main':
0 ^% I# B7 o5 @- i2 b# T# e 3 crtmq.c:(.text+0x31): undefined reference to `mq_open'
" c( d- @/ z4 g9 o6 m 4 crtmq.c:(.text+0x60): undefined reference to `mq_close'. s' B2 H: y$ M/ j' ~
5 crtmq.c:(.text+0x8f): undefined reference to `mq_unlink'& ~: K$ f) v4 w4 R& b! W: Q7 n( n
6 collect2: ld returned 1 exit status0 N8 j" b* N9 {( \& t5 T3 H- h
7 因为mq_XXX()函数不是标准库函数,链接时需要指定;库-lrt;
" h& ?# U5 U; M' y3 D 8 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c -lrt
: V6 G2 [& O% }( m6 H) @/ @ 9
) H: ?$ X2 p' M& E7 v9 S! i6 `* P# p10 root@linux:/mnt/hgfs/C_libary# ./crtmq
5 _ i3 `) D1 m9 {6 R11 最后程序并没有删除消息队列(消息队列有随内核持续性),如再次执行该程序则会给出错误信息:
5 y! @" }0 ^. B- Y12 root@linux:/mnt/hgfs/C_libary# ./crtmq 8 F& L" G0 _! I$ y
13 创建MQ失败: File exit(0): H- C2 y( t# W1 `$ c
0 \; C+ N) I Z: [* y
* M; E0 \9 m2 a2 K
7 S0 Y5 \) P8 Q0 ^& S
编译这个程序需要注意几点:4 A0 ?, W. m3 M2 O% L; q
- J- }1 M& c% b2 |4 [- W- o1、消息队列的名字最好使用“/”打头,并且只有一个“/”的名字。否则可能出现移植性问题;(还需保证在根目录有写权限,为了方便我在root权限下测试)
: u; `% l h( [! [5 O6 C2、创建成功的消息队列不一定能看到,使用一些方法也可以看到,本文不做介绍; _. X: n* D* R. `% K X
; Q8 T0 l5 t* A( c4 B4 _) v. O! w
消息队列的名字有如此规定,引用《UNIX网络编程 卷2》的相关描述: mq_open,sem_open,shm_open这三个函数的第一个参数是
% ^7 P* k: ^! _4 N+ `一个IPC名字,它可能是某个文件系统中的一个真正存在的路径名,也可能不是。Posix.1是这样描述Posix IPC名字的。 ' X7 F& ^ g! i; k, F) {: d. v
1)它必须符合已有的路径名规则(最多由PATH_MAX个字节构成,包括结尾的空字节)
/ g9 s6 f5 ?* D- }2)如果它以斜杠开头,那么对这些函数的不同调用将访问同一个队列,否则效果取决于实现(也就是效果没有标准化)
* q0 x; Z; C V; Q3)名字中的额外的斜杠符的解释由实现定义(同样是没有标准化) 因此,为便于移植起见,Posix IPC名字必须以一个斜杠打头,并且不能再包含任何其他斜杠符。/ y$ J/ d* a n5 ~# o% m, D+ g
$ ^: w6 v$ J3 Z! T8 P# H! I5 C' {
4 H5 D ]) I- ]9 h
IPC通信:Posix消息队列读,写
' X5 D. W2 m5 J+ B. ~! {( P- O9 y* ^# I6 r! ^/ L
创建消息队列的程序:' ~: g* a* e: { v& x
$ F: r3 v( v" b- z, |! l/ V7 i 1 #include <stdio.h>
~, s3 d w6 ~/ K 2 #include <stdlib.h>
4 m1 f* A4 F% `$ ]% x; [* U 3 #include <mqueue.h> //头文件* z* R; r8 |& c, {9 y1 I
4 #include <sys/types.h>
" T) t8 D/ [6 ?$ h! T) } X 5 #include <sys/stat.h>
0 Y% r7 T/ r" w5 p- \& r 6 #include <unistd.h> 0 [. z: V" p) y( Z, {! G
7 #include <fcntl.h> 4 f0 \' `7 I& m7 v' V
8 #include <errno.h>
5 q8 ?% O9 _6 S8 b6 V# h5 T 9 ; ~6 B- L4 O& q" S
10 #define MQ_NAME ("/tmp")
; K- C" F8 Q. G0 i* T* a: `' k11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag ; }3 W% H6 f) w! G
12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限 4 J$ B- H4 s$ c% b% K8 h
13 6 h L1 j& E$ V+ L: G. u$ q; M* m
14 int main() $ T! A. r1 z" i2 [4 F6 {+ Q: N) Y
15
' r; [1 J, \' i' l16 {
9 t- q3 _' l( ?" j: L: F17 mqd_t posixmq;
! T% W+ h/ Y Y Z/ \4 h& r18 int rc = 0; - f) a1 ~6 f. u5 Y# F. Q0 F4 H
19
. M9 V7 f8 `% L20 /* , U4 m) k/ m* z, a% S: T+ V+ |0 j
21 函数说明:函数创建或打开一个消息队列
_# o! S1 {' {2 W6 i0 [, L22 返回值:成功返回消息队列描述符,失败返回-1,错误原因存于errno中
, ^5 P; ^' B* a4 J5 _23 */
# M h& Q' P& p7 f; z24 posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);
5 D s; ^( z+ @; l4 U$ b& k' N25 ( X4 O3 Y7 E* B0 ~6 ]0 r
26 if(-1 == posixmq)
' a" s( [+ H: ]8 K: |6 e' A27 {
+ k! w5 i' k9 f" U28 perror("创建MQ失败"); ) B, j$ {+ H; ]3 G& R& ?5 M
29 exit(1);
% N* [. c' J, u. B; C9 B7 b0 ^30 }
6 _, a& E- I6 T* r31 - X8 _2 i W8 I M& a W
32 /*
% m; n+ h& r9 }( J4 f1 Y7 I33 函数说明:关闭一个打开的消息队列,表示本进程不再对该消息队列读写 " [) ?! l8 b& [7 e, y* r* b* S
34 返回值:成功返回0,失败返回-1,错误原因存于errno中
) G7 ]& N! `3 W1 S/ ]35 */ ( M) t* _& C9 ~6 W3 H$ r! N
36 rc = mq_close(posixmq);
( A8 m8 I& Y4 Q0 T1 B. y. F37 if(0 != rc)
( m1 q3 _$ ?' ]: Z- K38 {
8 Q! R2 D! k5 C! E39 perror("关闭失败");
3 @) i7 l7 l7 M9 ~) t40 exit(1);
7 R R4 j0 G8 g% c' K9 x" x41 } 2 i# w4 f8 |7 ~; r P$ f! v6 V! i# s
42
. B1 u0 J( b8 v43 #if 0& O0 @! m9 k- u5 X8 d
44 /* * e- f% V8 q5 k) b$ `' @
45 函数说明:删除一个消息队列,好比删除一个文件,其他进程再也无法访问 , m$ [ {2 ?( A3 Y0 ^
46 返回值:成功返回0,失败返回-1,错误原因存于errno中 3 q3 F" W, _" Q+ ~1 ^5 _! f
47 */
5 [! t G( a @$ H48 rc = mq_unlink(MQ_NAME);
$ d% S' {% L- p( C! B% Y6 I49 if(0 != rc)
0 U t% \' K1 H. G0 [/ R50 {
( a0 c: a; x- @7 Q/ |51 perror("删除失败");
* A' M' W: M6 \1 ^4 |( t+ Q+ h52 exit(1); 9 Y/ l. ~! ^' d
53 } ! Z8 z1 e3 W, U1 m
54 ' ^. v/ `! V. J% p
55 return 0;
; q0 J: i1 A. L56 #endif
# B. a8 ^' H4 U0 M) m N% x57 } 2 x' m4 q: ^, m8 O
2 u3 r* K0 y/ M2 u. p- C/ a& O* x) U7 Z) q: v8 {2 t4 e2 C
1 ^6 V) R& q+ }. ^. ]4 v# u
编译并执行:% O: r6 J5 R+ p6 k; S q+ R
- g7 B3 b D5 |$ A o
1 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c -lrt- @+ N* O/ Y2 h& T8 u' N
2 root@linux:/mnt/hgfs/C_libary# ./crtmq5 j4 W9 q8 O/ g+ c2 J9 J9 a
3 程序并没有删除消息队列(消息队列有随内核持续性),如再次执行该程序则会给出错误信息: . k; `, v" K# S1 n
4 root@linux:/mnt/hgfs/C_libary# ./crtmq & v+ j# n! U" @! J$ G* y. w3 W
5 创建MQ失败: File exit(0)) p, r, U3 M* [, y0 M5 h; r
! @7 v+ w! Y0 f8 d2 [0 V& _* k
0 F: b. i* P d向消息队列写消息的程序:
7 u& c; y* Q$ d) L, e8 B( E" A% j( o$ ]% h% _! X
- 消息队列的读写主要使用下面两个函数:
- /*头文件*/
- #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 */
- };
" t( b% T5 U1 o7 E( @. I2 I/ F j
2 R0 J3 J5 D% G* l. y4 Y: J
/ [; F5 {* f5 d. ]/ J# V' @- M. v
8 c: K/ R9 }/ q- g* H: N2 F& B0 T5 d" K
' E6 _3 e6 E' f# G) \ 1 #include <stdio.h> ( `% C/ ^& A2 O) Z$ h
2 #include <stdlib.h> Z4 [5 N* p- `# v3 v
3 #include <mqueue.h> - x! i0 f- j/ J9 `
4 #include <sys/types.h>
; @, ]( a' F* Y: u0 C- K7 l 5 #include <sys/stat.h>
! C* g; I w8 [* I' {4 x 6 #include <unistd.h> ' f W$ L" z% G* v6 |: S0 I4 x
7 #include <fcntl.h>
7 N/ M! L- |0 d$ t, r 8 #include <errno.h>
; E$ O0 _' i5 i4 d, J; u2 | 9 4 U1 j' g( U; w7 n5 J* U
10 /*向消息队列发送消息,消息队列名及发送的信息通过参数传递*/ . T9 ^, U1 w+ x7 v$ r; K! B/ R# ?
11 int main(int argc, char *argv[]) ; u! u4 E2 H: e" W5 v
12 {
4 @2 R% m9 J' n; B( e$ w+ B5 X13 mqd_t mqd; 8 w: R. G V# ^3 w1 Y5 v; c9 V6 {
14 char *ptr;
# C/ C' U9 z/ \- }9 E2 f- {: ^15 size_t len; # H1 Z7 m3 A$ G% J2 s* n$ O
16 unsigned int prio; + h1 \8 B9 f; }3 }, A6 P
17 int rc; . }. U- Z" e# c) `/ E4 [* J
18
) d/ K( n4 t/ }5 t* d19 if(argc != 4)
5 u- T P1 {5 r# E! m/ |20 { 1 {7 a/ d& U$ ^* C8 U8 P
21 printf("Usage: sendmq <name> <bytes> <priority>\n"); . P/ Q7 @; S Z3 H9 y5 T; A% y
22 exit(1); 5 U% k* r* l3 [/ B6 A& J" b
23 }
- c' U" J& i4 k+ a3 L* Z4 I24 5 C" V7 n& W+ `
25 len = atoi(argv[2]); 9 u; W1 q+ `4 x# m' Y
26 prio = atoi(argv[3]); % ~9 w6 a/ w4 M3 ]/ P
27
& z4 `! p, S8 s* b0 Q28 //只写模式找开消息队列 9 m6 C5 y$ Y0 a) |7 J, k
29 mqd = mq_open(argv[1], O_WRONLY);
$ {2 q% }9 p9 k1 Z1 m1 M30 if(-1 == mqd) 5 n! b7 A2 @/ h
31 {
" v/ M3 t. V1 G$ ^" i2 L" X32 perror("打开消息队列失败"); $ d) g% B' D& d0 s x% w- N
33 exit(1);
; [* L4 j% ?' |& ~6 i34 }
9 R# H5 P2 s- Q. n$ H- S35
( [% B6 q$ }9 Y( j36 // 动态申请一块内存 5 o9 \* z; U2 }: t6 }2 y9 G
37 ptr = (char *) calloc(len, sizeof(char)); \4 Q2 I- M( j4 t5 ?
38 if(NULL == ptr) $ _! Z+ G+ g/ S8 T7 f
39 {
* T; G" w& F. H# k6 }& L$ { V40 perror("申请内存失败");
3 k4 \0 [# ^/ m; P$ m1 m: L41 mq_close(mqd);
7 _$ z( @5 I6 q+ U6 w$ t! _42 exit(1);
+ j& R P4 E n9 }0 d43 } 5 C& i/ S( G2 @2 {! D) h6 A
44 % I$ V. j) v" _
45 /*向消息队列写入消息,如消息队列满则阻塞,直到消息队列有空闲时再写入*/ 9 V+ j; G$ F9 ]4 S3 u' H+ M
46 rc = mq_send(mqd, ptr, len, prio);
4 v; U3 c) k1 @& a47 if(rc < 0) 3 u" T& L: J) m' t% e& e& W9 @
48 {
. m% Z$ p/ k: u. `+ u7 C49 perror("写入消息队列失败");
: L. z" K$ H* Q50 mq_close(mqd); . d9 A& C* p; i9 i) O) E
51 exit(1);
$ K2 q$ b7 I' I) |/ j5 S& v9 n( o8 ~52 } 3 x- K; L$ g8 {, \0 X
53 : R" l& \. c( N3 J7 D8 V6 {; Q( G
54 // 释放内存 0 Q) [ z6 P+ K0 G
55 free(ptr); & w3 X' S; D* C( o; q, j
56 return 0;
8 A- Q4 f2 V% S3 K; e5 P5 Y$ O57 } 1 `" X4 z5 N( _' B; Z( Q/ w5 \
$ _8 L3 r; B2 b2 l) u0 ` B& g5 `# c6 N* @ o/ G
编译并执行:/ g1 p: H8 H# w
, x2 r' e1 T4 i
1 root@linux:/mnt/hgfs/C_libary# gcc -o sendmq sendmq.c -lrt
4 P6 \0 T C1 P! K2 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 151 H# r7 S6 @; \
3 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 16
' L# X: |* h0 N) F/ V4 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 170 f9 Z' v7 E ~- Q/ Y
5 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 18# A) c+ z g; X
; D' i% R' K3 J( X7 {- p3 y: |% k# ?; d
上面先后向消息队列“/tmp”写入了四条消息,因为先前创建的消息队列只允许存放3条消息,本次第四次写入时程序会阻塞。直到有另外进程从消息队列取走消息后本次写入才成功返回。9 {- m3 y5 [" [
) w* f; H1 i! J
7 _2 ?2 }. w9 ]! J& Z3 L6 ~* T" f0 K3 u( y, b
读消息队列:) X4 X% K" j7 F% t& q
* J8 D+ S4 q) A# U; {#include <stdio.h> & b9 V: p/ t: Z. O
#include <stdlib.h> 9 ~% L$ c' T. S/ r1 g0 a8 H$ e: [0 y9 p
#include <mqueue.h>
- B+ X# t/ ]3 D9 `- |#include <sys/types.h>
" g' c1 {5 K6 ~1 J5 `) R#include <sys/stat.h> % I& z, _) }2 r' y z G
#include <unistd.h>
9 N1 {9 w' e* I' M. X& h#include <fcntl.h>
2 z, y& s! ]: @8 H#include <errno.h> ( F/ K. U* E( Q; |5 n$ r6 v
' [9 O; T. k0 R/*读取某消息队列,消息队列名通过参数传递*/
' V) r A8 ]* F& i. ?; P5 Jint main(int argc, char *argv[]) ; W3 Q8 j% f* O/ q% |
{ ( p3 B) F5 W' v
mqd_t mqd;
' L( e; R3 E# @9 j, u- P( r struct mq_attr attr;
; {1 D# q! @7 n: [ char *ptr;
# e4 j$ }' g2 B0 ` unsigned int prio;
6 e+ F, ?, z5 b. ]; ?9 N size_t n; - l" g+ D) w' Q2 Z/ y' [
int rc; ! G4 N7 @6 k% ^& k8 h
" p$ ~: ?# c2 O* l* ?$ q9 x! ]
if(argc != 2) b; e, g$ N4 e
{
) M" F; y( \0 J2 n0 n( @/ D- v printf("Usage: readmq <name>\n");
7 ^' x& i- m3 v# M! j% j8 z# M exit(1);
6 A7 n$ [. g' i }
+ U0 Y, U6 M) E* f8 v' d# f$ f; e0 U: c( Y; j7 F
/*只读模式打开消息队列*/
9 l0 F5 @. z2 ^- z/ w5 D1 F mqd = mq_open(argv[1], O_RDONLY); & r* M t$ `& j( V$ {+ y0 H
if(mqd < 0) * O, g9 y7 K, m
{ x4 v- m/ [8 {" g( y. H
perror("打开消息队列失败"); ! v, q% V, s$ k- ]8 H
exit(1);
& x$ [* A8 i# }5 G } ( ^9 F6 `5 Q* b6 f* O# _
& z, o T; e" O
// 取得消息队列属性,根据mq_msgsize动态申请内存
5 P" y. Q) a6 M6 n Y% |, n rc = mq_getattr(mqd, &attr); 4 f. z' d# w. _1 L) S
if(rc < 0) 2 _4 T P: g5 f) e
{
* M7 }: f: {3 V( ^5 x {' V perror("取得消息队列属性失败");
0 m. h# `* \5 u* e' g5 P. O6 | exit(1); " q4 B9 T, ~ f- R
} ( G0 O5 E% ^- Y: u' I& }5 y
( k# I% M0 U$ }) r, O /*动态申请保证能存放单条消息的内存*/ ) p( Q! _' V1 a" O
ptr = calloc(attr.mq_msgsize, sizeof(char));
8 E, w7 o- o4 X+ d: K if(NULL == ptr)
3 d: F" n8 f. M {
0 i, X! R7 ]! o& s1 K( r) h printf("动态申请内存失败\n"); ) U5 y d# B- N: `. J
mq_close(mqd);
, x/ g I% Q p: H& u exit(1);
% q2 _7 ]% s' ~ } 3 ~ e( ?- s: O O% U
6 r5 l* W- }/ n* Q* D9 } /*接收一条消息*/
7 H. a- o. O; _0 A5 ~7 o n = mq_receive(mqd, ptr, attr.mq_msgsize, &prio);
1 `+ k8 n# G1 q9 W: P7 d, h' N if(n < 0) 6 l# d+ F7 D, [: e* E
{
6 A, G" K8 M! \' L) s perror("读取失败"); ; A8 {; t0 b0 [$ S
mq_close(mqd);
) Z0 E( ~2 D; E- }5 J) O free(ptr);
& C O3 M7 r0 P exit(1); 6 _' A- \7 T8 Q( e. D/ J& }
} 9 p& M6 V/ ~: u( y8 z6 R! t" g' x
7 c! {% t: f2 n( ^
printf("读取 %ld 字节\n 优先级为 %u\n", (long)n, prio);
5 t- a1 g8 K6 p- y1 k$ y/ t- L return 0;
* m2 [2 j$ b/ I- Z+ Q+ m}
) v8 f4 A% |0 e& N0 p$ l0 ]9 y4 B
' z v D3 n$ u4 d8 A& n& O7 D" j9 L- f* m) m: c- n
' u( X+ N F1 z$ x
编译并执行:; ?0 o8 U6 K s1 z6 b# H
) U; L7 X1 ^$ u 1 root@linux:/mnt/hgfs/C_libary# vi readmq.c
9 _! y& p. ?2 Q/ Z i: L3 e! c 2 root@linux:/mnt/hgfs/C_libary# vi readmq.c
7 U7 |) Q0 H$ t6 K( ? 3 root@linux:/mnt/hgfs/C_libary# gcc -o readmq readmq.c -lrt
& Q3 V8 v4 C6 h- c. h, W 4 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
9 w: o1 B% j! C8 V 5 读取 30 字节
& u9 Z5 l/ |! Y. A: i0 E+ V 6 优先级为 18( g" f5 x9 B% G L, N& p
7 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp, S' v! J5 @% R7 h9 R& n2 B$ a' b
8 读取 30 字节3 s' q) s( l( V5 |+ k8 i0 j* {
9 优先级为 17
! Q, {9 G0 M! T. s10 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp Q0 q0 P/ d- i m ?: z$ ?6 }
11 读取 30 字节3 x' ?$ n1 B7 C
12 优先级为 16
# v: E( A4 h# `% G13 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
, O) t, ^. h5 g% E8 U! E- z14 读取 30 字节5 C7 [0 |! e! X! e, ~
15 优先级为 15
! U$ ~ w3 j8 l3 i( F" U9 I16 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp# m' S& I0 Z, q8 i
+ H- W& i3 _: p7 @+ n) [
! T5 t2 K5 u* A4 P) a! E0 r# W, ]2 e2 o" {9 T ?& |3 `' U3 e& K; p
程序执行五次,第一次执行完,先前阻塞在写处的程序成功返回。第五次执行,因为消息队列已经为空,程序阻塞。直到另外的进程向消息队列写入一条消息。另外,还可以看出Posix消息队列每次读出的都是消息队列中优先级最高的消息。
" Z+ Q) q3 m9 i" H* \' T9 P
& Y* N/ @$ W( m
3 Y1 ?9 D0 o) A: B; r I6 f5 w/ \" x+ k3 V3 z& `3 q$ q
IPC通信:Posix消息队列的属性设置: V+ V9 C# \3 v
5 b4 |* @" j; j4 T0 |9 u1 j, g+ ?- 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,若出错为-13 B( Z2 ]3 m/ F% ~% c6 Y
+ l2 F( K0 L; X n- r) y5 u2 {
t! H( K6 s! j# x( k3 P程序获取和设置消息队列的默认属性:
& s+ F2 K+ D V# G# h2 p9 t- e5 e' O$ b6 l- I- Y1 v* K
1 #include <stdio.h> 1 _$ H G) _/ K0 Z6 _( b3 _
2 #include <stdlib.h> * k& }5 D8 e: |6 K* j1 ^0 R, ^
3 #include <mqueue.h> , B0 ^! T' Y) b/ ]8 Z& w+ V6 ]! N
4 #include <sys/types.h> " j3 h9 k$ t1 V' p0 c- t
5 #include <sys/stat.h> $ F) |9 b0 R. }) y. L0 Q1 k
6 #include <unistd.h>
5 h) b# Y5 i* r$ ^# m! r+ A6 D! J 7 #include <fcntl.h> ! H& k; f: v( F4 L0 `; e+ z0 `
8 #include <errno.h> 1 y" t$ r ^& Z! b4 K6 r8 M
9 $ x& T7 _4 u4 s' B' @. f; P4 y7 u
10 #define MQ_NAME ("/tmp")
' A) S! h* O: c K11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag ) w, E# j4 @+ v. c, E1 B
12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限
9 T1 [9 P! D- Q( o, Y$ ?5 e- F. D+ o13
) s0 V$ J' T! Z3 j4 ]14 int main() : `' _2 b. `7 B3 c0 r
15 { 6 Q! r) H3 }' `$ [, f/ i% E Z6 N
16 mqd_t posixmq;
4 H( _7 ]0 Y+ r4 u. K17 int rc = 0;
# C% _6 p: h7 u- E a& v, A& J18 ' `6 i6 {. \ U) |
19 struct mq_attr mqattr;
5 _% s- ]: `4 N1 G/ v: C; Q4 i20 8 n5 [% V* `& Q( V- F+ u
21 // 创建默认属性的消息队列 % y, c0 w6 A- T: n8 s) `
22 posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL); 4 L/ I$ {% ]; \( ~( e2 q: t
23 if(-1 == posixmq)
# {- o$ N: ^; F* B. G$ `24 {
l* K& }( ^$ ~( K% W25 perror("创建MQ失败"); # D# N1 p: [1 x8 h/ z. C$ e+ F1 D* p$ q
26 exit(1);
. S# B2 A6 m& O27 } 3 G& n Z1 j. b; g4 F
28 0 k" D' \/ Z. m9 S/ `
29 // 获取消息队列的默认属性
. G6 Q5 U0 y3 S! M8 z2 p30 rc = mq_getattr(posixmq, &mqattr);
% ` ]9 E7 D* N$ \! y# d( q31 if(-1 == rc)
0 m5 b1 q. l; V+ m9 Y1 ?! m32 {
( |0 n* {/ O( ~+ K! l3 P33 perror("获取消息队列属性失败");
/ o; z4 q6 t; d* k2 J" u; h6 e34 exit(1);
4 l1 J1 K0 e4 {( |4 |5 d( ~$ D2 E35 } $ @* t3 j; r, T' f9 o- r
36
5 r# d5 |0 s- Y7 b' o* Q H37 printf("队列阻塞标志位:%ld\n", mqattr.mq_flags);
- q( s2 P: q- T' b# X8 g38 printf("队列允许最大消息数:%ld\n", mqattr.mq_maxmsg);
2 J& m( I5 G5 t2 ]" {) A39 printf("队列消息最大字节数:%ld\n", mqattr.mq_msgsize); ( V2 R( h6 o9 K. i' e% R8 L+ R0 j2 {/ H+ i
40 printf("队列当前消息条数:%ld\n", mqattr.mq_curmsgs); 2 |! J. @/ D) h) X
41 " D3 G* y% @, s! h/ @0 c
42 rc = mq_close(posixmq); 0 p1 x0 V+ w0 \, L; T
43 if(0 != rc)
8 G, W9 |/ ?+ k44 {
" }0 H3 _% Z* p$ a45 perror("关闭失败"); - d+ c" Z) I; a( g& n
46 exit(1); " j4 c" F8 V0 k0 X
47 }
3 m: q% y( ?4 }- Q9 Q1 Q. I7 H* [48
) H3 ]" G- Z$ T49 rc = mq_unlink(MQ_NAME);
' R8 ~' q( S) v1 @50 if(0 != rc) 3 K/ u7 B6 N7 W* P' h
51 {
4 c; I n) c2 Q52 perror("删除失败");
% v1 [! a4 ~* a" J8 \0 J53 exit(1);
3 q5 }7 g% N6 M0 ]54 } 1 m. b2 {, u" l) C {1 n
55 return 0;
4 @* a) R% z: M! H6 Y56 } 9 }7 m4 E/ |5 N' T
0 c: ]! m# F; ^$ |* E
; f; n7 M% \' }& N x
编译并执行:( f3 B( J/ m+ {
" ?! b! Y4 L5 m" L1 root@linux:/mnt/hgfs/C_libary# gcc -o attrmq attrmq.c -lrt1 o& q# Q5 q5 u9 E5 K) N, L" h
2 root@linux:/mnt/hgfs/C_libary# ./attrmq% _" U0 F2 q& m" [% i, P
3 队列阻塞标志位:02 j4 x$ h( d4 {" ~9 ^$ V
4 队列允许最大消息数:10+ y9 t3 Q& S- l/ ^% C
5 队列消息最大字节数:8192
* u$ u5 `) s/ K6 队列当前消息条数:0
7 R: n' k- Z9 M9 e7 root@linux:/mnt/hgfs/C_libary# # T9 @, @' T# d5 @0 k ~) ^
: g+ e2 q0 K9 L3 Y! o9 \0 k9 {5 m
6 q6 ?0 J- h( o9 t1 Q0 q- {( e& z; J设置消息队列的属性:' b7 \, _0 Y6 c" b$ i
9 k- l# l4 Y" P# W# v$ @# d6 Z 1 #include <stdio.h> ) C' Y: M) h, k( G, H
2 #include <stdlib.h>
3 B8 v; B* t2 M b3 a( j! C% ] 3 #include <mqueue.h>
5 |9 ]4 h$ j& \, G4 w+ g 4 #include <sys/types.h> 6 e9 _/ z, T2 S2 i
5 #include <sys/stat.h>
- f( ]; o4 c j' g; | 6 #include <unistd.h>
$ P$ R- e* [' \: Y1 T3 U 7 #include <fcntl.h> ) m2 X' |* Q& v9 f
8 #include <errno.h>
9 h9 X( K" C! Q" S7 Q' d4 d 9 - H' v# I8 }* e s
10 #define MQ_NAME ("/tmp") ; C* n$ A5 ]; E" J7 |, p! e
11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag
+ L2 F p% N# d; h8 {0 v0 D5 D+ p12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限
# Y9 W9 p/ T! }) ]4 H13
9 I7 N6 V Y! [* c7 U14 int main()
1 ~; X. `; x, m! h, V7 B15 { & S) {1 l- t8 ~% R, s# t4 I) U
16 mqd_t posixmq; * k+ B I1 v% F- ~$ V
17 int rc = 0;
% |) U" g/ P. w* z" ?4 h% ^18
, O# S" A2 R' ]- }19 struct mq_attr mqattr; ; a, x) [8 a) W+ K! R4 ?5 e* m1 p
20 ! q- k5 R1 g5 C. V8 B7 N: g6 [2 F
21 // 创建默认属性的消息队列
, {! i9 y# I7 ]+ v& [& X4 H22 mqattr.mq_maxmsg = 5; // 注意不能超过系统最大限制 + |$ Y* \8 d( o, i% F
23 mqattr.mq_msgsize = 8192; $ f9 G3 [8 J. a8 s& U' ?2 x' O. `
24 //posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL); , {1 m' d1 v* C* e
25 posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, &mqattr); - j' ~0 K6 D2 X2 l; {
26 & {$ P5 Q" b4 R4 P ?" Q+ Y
27 if(-1 == posixmq) & c: U( Q ^( S1 D
28 { 0 @7 F# f& u" H* w/ p" r
29 perror("创建MQ失败");
+ E: ?& B% T/ C. h/ i) g% a' `: @30 exit(1);
; Y$ e& A6 V" h1 r31 } # r( K% y9 O+ Y& A
32 1 M# l8 ]* Z0 r: B& E
33 mqattr.mq_flags = 0;
4 Y% a4 b' @ F3 I* N O* v34 mq_setattr(posixmq, &mqattr, NULL);// mq_setattr()只关注mq_flags,adw
; }! K# K: |5 W$ N35
/ x7 I' M& W- T D5 u7 F36 // 获取消息队列的属性
9 U. f; i7 G8 ~( @9 E37 rc = mq_getattr(posixmq, &mqattr);
1 H; i0 }" c0 L0 `5 v38 if(-1 == rc) 6 s* v$ t' E5 l/ f$ w1 _7 l; f/ O
39 {
; T8 B& a& T4 e40 perror("获取消息队列属性失败"); 8 v2 s8 z4 r3 R
41 exit(1);
0 L7 W' }+ |! o8 x42 } f" Y- s( c! g6 x2 i# y% y/ H- B
43
# U1 C. ]+ d# N7 e; A6 g44 printf("队列阻塞标志位:%ld\n", mqattr.mq_flags);
9 ?9 c4 ~, f8 L' M, H) w45 printf("队列允许最大消息数:%ld\n", mqattr.mq_maxmsg); , P) Z5 @7 i" a1 F) u6 j( L
46 printf("队列消息最大字节数:%ld\n", mqattr.mq_msgsize);
0 p& ^6 A4 S6 ]: o) ?3 [) _47 printf("队列当前消息条数:%ld\n", mqattr.mq_curmsgs); : b4 f5 p) l/ W' E2 ]2 E
48 1 f0 z% ~' }: P6 C
49 rc = mq_close(posixmq); 0 R) M. o4 K9 v7 u8 p( v- W
50 if(0 != rc)
, a4 L$ u( t2 X1 v51 {
, V3 _8 {& u3 H% c2 [52 perror("关闭失败"); - H* h6 t7 S6 ?$ u" N
53 exit(1); % S2 N; L4 I2 n: W8 J+ M4 e
54 } # w5 j f9 p* Z4 E7 L! d @5 J& E9 b
55 " O1 U& ^+ {6 }8 F7 @
56 rc = mq_unlink(MQ_NAME); # I0 z9 p7 T6 V0 [1 d7 v
57 if(0 != rc) / i+ D' U5 J& r* r- }; S/ H
58 {
, O$ A& m: o/ [6 O6 D7 Z# J+ [59 perror("删除失败");
6 S" N y2 m4 A! R; Y60 exit(1); F, ^! T z8 h! @* [, |' O# _# i M
61 }
. S' j$ j' `; Q; O9 U% N) V. |62 % Q) x3 j2 a2 H' f' b
63 return 0; : {; ]6 |' c% H9 e6 M
64 }
( x0 }/ C& R: v7 p+ z: q4 y+ E+ o) V- C3 S
9 ^1 q; Q5 B( V4 J编译运行:
. J$ y5 Z' W% i0 @" i) y. x- U# J
1 root@linux:/mnt/hgfs/C_libary# gcc -o setattrmq setattrmq.c -lrt
; Q: w2 [& ^, d2 root@linux:/mnt/hgfs/C_libary# ./setattrmq* f$ x5 o1 n5 L( H+ S! o& a2 o$ ?; w" _
3 队列阻塞标志位:0
2 d' M7 L( d% I2 k& m0 }3 P4 队列允许最大消息数:5
9 \* \0 ~( c- Y) K! ^+ j' _1 S5 队列消息最大字节数:8192
9 Z0 G4 ^5 z4 t/ r l6 队列当前消息条数:0
( d b. l+ u- p/ S4 g0 h
5 |( o/ n1 S. p, n
" B' e5 s; Z$ o3 r3 B+ T0 G8 b; r) W6 Z! X# C
* {% U9 N4 l2 a$ E T B6 {% Z
5 d0 Z+ c0 J5 H. I" p; c. t& g( e& ^! w; K; g3 d
5 o4 O) ^" M9 e
( t- ^& T1 t! x2 t( U1 l$ R9 E
( t& i8 y& k# V
4 V# m6 g9 Y+ s7 \0 k. E/ {8 Y' Z3 G$ x I
|
|