|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
6 P9 P7 v" M! W7 b, g
消息队列可以认为是一个链表。进程(线程)可以往里写消息,也可以从里面取出消息。一个进程可以往某个消息队列里写消息,然后终止,另一个进程随时可以从消息队列里取走这些消息。这里也说明了,消息队列具有随内核的持续性,也就是系统不重启,消息队列永久存在。
1 o5 y9 C, ?) U6 H# B+ a/ E' b; {9 n0 k- d
创建(并打开)、关闭、删除一个消息队列, f! ~: j6 c/ B: p- H4 c* s
: c! C, m) x; p, P% }
1 #include <stdio.h> 0 l+ c- C' [' `: \/ h0 Q/ ~
2 #include <stdlib.h> % R9 h4 @/ V- c) q9 h' P
3 #include <mqueue.h> //头文件
0 t% \! E' [( s- b! _4 Z4 i 4 #include <sys/types.h>
4 K7 B" t# M7 i4 l 5 #include <sys/stat.h>
0 X' R; `9 L [' S ^ 6 #include <unistd.h> ; z- J; r6 O# m6 `$ {
7 #include <fcntl.h> / y7 U5 n' o1 E3 `! P ?( z
8 #include <errno.h> ; m' E' H9 i8 q y; X0 ^, K# I
9 5 C% o& `* Y9 L1 `* z2 u
10 #define MQ_NAME ("/tmp") 8 E4 R5 U9 K7 ^2 @
11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag
8 c- v; |# i- m% b( x12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限 ( [! P, j# f! \# m
13
7 j% k j! c4 e, Y14 int main() 5 M, E. |! A8 }3 d k/ A, f0 v
15
& ?( }+ @ T; d0 ~16 { & z, W7 L4 m5 w
17 mqd_t posixmq;
" U/ O$ H2 Q/ F! x q2 y; D18 int rc = 0;
6 |- M( @3 z: V4 {2 B N; k7 b' z$ k19 * K. j5 {; A* i# R) W) B
20 /*
1 V9 x. U' U/ V9 ~1 W \1 `. w21 函数说明:函数创建或打开一个消息队列 7 o; U- v; G; m- B' h) z
22 返回值:成功返回消息队列描述符,失败返回-1,错误原因存于errno中
1 R4 u% }" W5 a3 L; U23 */ - W' Y6 y) e7 t6 y, w7 f$ n8 w( L8 l
24 posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);
2 R" x! ?9 C* r+ f7 w! |25
; r$ L: V8 | }, c b6 x26 if(-1 == posixmq) ) O% L) E9 S8 P, ?4 s( K) `
27 { : {2 a# e3 z$ g4 ~% @1 _& w3 M. [* q. K% u
28 perror("创建MQ失败"); ) S% f1 _5 O) y. U
29 exit(1); $ V/ a/ Q) O4 v0 O6 T
30 }
7 k9 O0 a2 a d! `4 n31
* u" z* b! \3 q32 /*
2 j( x- @/ r+ _7 m$ M" t33 函数说明:关闭一个打开的消息队列,表示本进程不再对该消息队列读写
% z" D$ f4 e) c3 M/ u) E) P' x: J34 返回值:成功返回0,失败返回-1,错误原因存于errno中
/ Y- O% v" Q+ Q& S2 a' \. c35 */ & ~8 c+ ?0 f% Z
36 rc = mq_close(posixmq);
2 H; X" b8 b2 i" P/ }% r3 c" m* d% O37 if(0 != rc) " s% ]5 Q& Z0 j
38 { # v) B- a3 E1 x. x# a, w {% q
39 perror("关闭失败");
( N* q3 c2 H1 ?1 }( e40 exit(1);
+ L$ k- x2 F3 b* L! i2 }41 } 1 K: ^7 j/ }* B
42 . m# S/ y! h! m3 b% j
43 /*
J- t9 r2 j( S9 a44 函数说明:删除一个消息队列,好比删除一个文件,其他进程再也无法访问 % Q3 Z) g" z# m
45 返回值:成功返回0,失败返回-1,错误原因存于errno中
& Y2 g) b+ ?, ?7 ^( u46 */
, K2 x" }( s- W- w: T47 rc = mq_unlink(MQ_NAME); ; z& a9 g$ r9 j2 I: n$ l* R
48 if(0 != rc)
+ r/ S C7 t/ Q8 S. E% n& ~. L d% c49 {
. K' K5 O4 P+ a50 perror("删除失败"); ; O% l6 n) W6 ?
51 exit(1);
$ i' H1 i! K! }! C52 } 3 e4 z: p- z/ ^" B+ g# o0 w
53 4 m8 Y0 B) G& O0 h+ s5 K: l
54 return 0; 5 X; s( {0 L5 u
55 } - b1 b2 `& S$ ^7 ] k
2 V' ~' A. `! z/ j, B
- w! x: i# ]5 J- m编译并执行:( {; m1 @5 j |( p$ E' H
+ \. a* |2 u& \2 T$ v* @( n5 i) k
1 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c9 ?4 b7 [3 M; S' Q C
2 /tmp/ccZ9cTxo.o: In function `main':
8 w$ D, x/ @$ c 3 crtmq.c:(.text+0x31): undefined reference to `mq_open'4 \/ D( M: v( z& ~* y2 x& }
4 crtmq.c:(.text+0x60): undefined reference to `mq_close'
) j2 `0 ]6 A; g9 M! n/ m 5 crtmq.c:(.text+0x8f): undefined reference to `mq_unlink'7 J* P6 b- F9 a" Y; D: Q
6 collect2: ld returned 1 exit status
% F% Y: \* C$ n 7 因为mq_XXX()函数不是标准库函数,链接时需要指定;库-lrt;/ B5 c0 M# [8 ]$ ?; r3 B% t
8 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c -lrt
1 _# E; P# M5 W. E3 w$ ^ 9
1 M- A8 T, I6 a/ I; s9 J( }10 root@linux:/mnt/hgfs/C_libary# ./crtmq
+ t3 S n9 o: z11 最后程序并没有删除消息队列(消息队列有随内核持续性),如再次执行该程序则会给出错误信息: ! s6 z2 K+ p) |' V" i5 w" k
12 root@linux:/mnt/hgfs/C_libary# ./crtmq $ W8 X* l1 ~5 d3 ~3 n! u9 Q7 n
13 创建MQ失败: File exit(0)7 }- b3 |: M% E" `2 L
. M0 ?+ }0 ^. W5 b9 |* X7 v3 T# ?6 ~4 [* N$ u$ {
9 E# w: O4 l5 h0 i9 _编译这个程序需要注意几点:
% m! ^" B+ T' k
E. T/ q$ N3 V1 K [1、消息队列的名字最好使用“/”打头,并且只有一个“/”的名字。否则可能出现移植性问题;(还需保证在根目录有写权限,为了方便我在root权限下测试), j/ T1 ?$ M3 v" }
2、创建成功的消息队列不一定能看到,使用一些方法也可以看到,本文不做介绍;5 M2 f3 D# K/ o. R
; I/ u; A0 l# F5 g+ f$ p/ \) d& p 消息队列的名字有如此规定,引用《UNIX网络编程 卷2》的相关描述: mq_open,sem_open,shm_open这三个函数的第一个参数是$ q( n! n, v* H! W( B
一个IPC名字,它可能是某个文件系统中的一个真正存在的路径名,也可能不是。Posix.1是这样描述Posix IPC名字的。
2 d: G2 J- U. l* u& U. U1)它必须符合已有的路径名规则(最多由PATH_MAX个字节构成,包括结尾的空字节) % R# t- E; }( ^4 h) X2 _0 m X
2)如果它以斜杠开头,那么对这些函数的不同调用将访问同一个队列,否则效果取决于实现(也就是效果没有标准化) * I1 x3 E* F" c: n2 u2 j8 S5 _
3)名字中的额外的斜杠符的解释由实现定义(同样是没有标准化) 因此,为便于移植起见,Posix IPC名字必须以一个斜杠打头,并且不能再包含任何其他斜杠符。" I. F0 B5 S3 Z K+ h% a
; B1 i* ?* G9 P
9 s% b% S! a8 \( QIPC通信:Posix消息队列读,写
" Y4 L7 s p. c. ?6 }
/ Z0 `% Z7 u( v- ?创建消息队列的程序:
9 {( q7 D$ u+ y! w* B/ C2 }
' z" O! N+ j. Q0 n 1 #include <stdio.h> . z2 g2 }8 @- r* K9 R$ M
2 #include <stdlib.h>
/ f# L: D3 O9 ?2 g 3 #include <mqueue.h> //头文件& g, U- y9 ~: d3 i" ^
4 #include <sys/types.h> ( ?- F7 R+ p+ j3 K D/ {8 J; S8 g
5 #include <sys/stat.h> $ Z( h# {3 M; A: W% ~1 ?9 X
6 #include <unistd.h> 0 Q! {5 C2 g6 I6 c+ \' T+ r! _
7 #include <fcntl.h>
+ n; X5 R7 R7 T1 { p. B 8 #include <errno.h> V! C1 M1 C. v: u: F( [
9 . Q" \* s5 @$ j+ [% q, v; n; Y
10 #define MQ_NAME ("/tmp") : w' d7 m& T: h4 B9 H) |
11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag
6 t4 _) M, ]4 k9 |& ]) s, H. h12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限
u. P: D8 p. {/ p) M) ^' s; h13 6 y2 S8 V7 m% m2 V0 Z5 v1 i; n. u
14 int main() ( y* E2 M# m* y$ Y# }
15 # q. c, ?3 J; x3 \4 N1 P
16 {
0 o% v* D7 ?' m17 mqd_t posixmq; ; j8 A# X+ ^, E% o8 q! _' S
18 int rc = 0; , a. z- I; {- A2 p# n- R
19 . _2 m+ d) F/ P
20 /* ; S$ e% U: w# S% [
21 函数说明:函数创建或打开一个消息队列
8 w, H$ _$ t; l, H) D/ _5 K22 返回值:成功返回消息队列描述符,失败返回-1,错误原因存于errno中
( @: {- ~- ^) m0 A3 y0 o9 X23 */ , t6 g0 }0 O: R! g9 D5 e+ V3 t
24 posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);
5 C2 Q1 d$ R) `5 R: d' J25
: n- e, }5 B3 E! N! n+ M26 if(-1 == posixmq)
7 v2 B* s; A. b1 L27 {
1 p2 V9 H& f& E28 perror("创建MQ失败");
' Q9 `' _1 K" V" }' }9 a2 V. \' P7 ]29 exit(1); 5 m$ Q+ L+ W4 r7 }
30 }
$ P' q# `' k/ w$ D4 d f31
( d' g- \" @2 B5 b3 Y: |32 /* * w. t1 s i. T' g3 ]4 x
33 函数说明:关闭一个打开的消息队列,表示本进程不再对该消息队列读写
{ I; m* c k, z7 p) z34 返回值:成功返回0,失败返回-1,错误原因存于errno中 " @: j! Z4 n1 W- I$ O- n- r% Y
35 */ 3 H3 x$ y8 V! `3 Q4 [; a7 z# ?
36 rc = mq_close(posixmq); ) y* Z2 F g$ j$ o9 z4 P
37 if(0 != rc)
. r2 ^- a- w/ D# z# w }. X- f7 E38 { $ B9 _( n u$ c/ Y
39 perror("关闭失败"); & j! e+ W R+ r2 U
40 exit(1); 9 }. J7 D% T5 k @( B( R* I7 B2 E9 ^
41 }
) H5 R( N# D3 Y/ n( w/ S* b42 * ]% y# \; v5 [( S' U
43 #if 0
. p, o, f. _5 T( @0 r2 ]44 /* \; G2 s, ?( v
45 函数说明:删除一个消息队列,好比删除一个文件,其他进程再也无法访问
6 n( K) A+ H# a5 V. i46 返回值:成功返回0,失败返回-1,错误原因存于errno中
& f7 y* Y3 ~5 I47 */% s9 c$ a8 d7 k( s9 }2 B
48 rc = mq_unlink(MQ_NAME);
k3 f5 q; p5 E$ N3 m c" a( F49 if(0 != rc)
. b1 d a/ _7 x' T50 {
* N7 q2 f' X; B( j. I51 perror("删除失败");
8 T# r" ?& q6 J0 M! |, {52 exit(1); , V& K+ B% |- }* o/ @7 E
53 } ) v" D: x0 K) g. G+ z2 L1 f
54 9 K0 R* B( e& r
55 return 0;
! \ j$ G0 k3 y$ q56 #endif 1 c' Q% K' F2 |+ s, b' U
57 } ' C. a4 z4 n, Z# ^( ^3 A/ }8 k7 O I
7 J; H2 t1 A: k, G/ G1 |
, K; s* p- o; w1 R \* `2 t: c0 C/ m
7 e5 R8 I3 Y( S# H9 Z. X$ {& w, X
编译并执行:- ~3 P) {5 u, l9 G" {
) s6 R6 Z3 p! L- _$ d1 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c -lrt
) C6 f1 f1 n. P2 root@linux:/mnt/hgfs/C_libary# ./crtmq
2 f1 i' g+ Y1 q* P. K& N3 程序并没有删除消息队列(消息队列有随内核持续性),如再次执行该程序则会给出错误信息: : W. `3 M8 y& Y8 s: Z% d* l
4 root@linux:/mnt/hgfs/C_libary# ./crtmq
2 P% R: Q9 _: E' j; Q, z2 h( U/ q5 创建MQ失败: File exit(0). P+ Z' n* K% O' ]0 `4 i9 Y& \. D
# o0 r o% s& ]% V' y7 y- Y) l6 O" P
向消息队列写消息的程序:
1 i5 j3 s, N# p# ?
9 R* Q. z2 c, s& s: c0 n- 消息队列的读写主要使用下面两个函数:
- /*头文件*/
- #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 */
- };5 T1 j2 C @1 _
% Y1 U7 o" c8 Q! q2 m" n. w! \
+ B6 v8 v' m- ^- K6 _1 w
1 ~& k0 p9 w- e9 E( O1 D/ U6 y9 F, V8 `7 R+ \, l- X
) Z0 G* `" c: K2 ]+ W2 g2 Y+ f 1 #include <stdio.h>
! T8 o7 E& R9 `; J 2 #include <stdlib.h> 9 X# c0 K. F7 x$ t5 S% n
3 #include <mqueue.h>
! t" y% F- h8 A- D: P 4 #include <sys/types.h> * W5 N' ?6 b G3 z8 \6 C+ j
5 #include <sys/stat.h> . W% S0 t4 P- c; d4 h; k1 Z* Y( j
6 #include <unistd.h>
+ O$ e+ @1 j; }- O2 k+ `: n- m: M 7 #include <fcntl.h>
3 f- j7 L8 T, s, f7 R 8 #include <errno.h>
3 @# A4 b- S6 `2 [ 9 ( [" V+ h& v+ r. W- i9 ?
10 /*向消息队列发送消息,消息队列名及发送的信息通过参数传递*/
& m# C9 }$ ]9 d/ V11 int main(int argc, char *argv[]) 1 I3 |2 E! z4 G5 o4 z
12 { $ s' Q# k S( Y& j8 \9 M
13 mqd_t mqd;
! T) q7 R! t$ n5 s! R% F14 char *ptr;
+ ]' N; J4 z4 w0 J; ^/ D8 [15 size_t len; # Q. m4 f8 o" Y4 j
16 unsigned int prio;
& g& w1 U7 A& t6 u: X0 n0 X17 int rc; 7 X, N/ X: A, I: x
18
; }7 W, }& S0 d# H' z# M+ o19 if(argc != 4)
4 Z x4 q/ t. L; C* |2 Y! x, _5 n20 {
3 j! c* {7 `* ~5 F9 f) s21 printf("Usage: sendmq <name> <bytes> <priority>\n");
2 `0 E$ _. W4 K% R% _22 exit(1);
g9 A- m/ b9 a23 } 9 r3 \/ [7 D* b6 B1 b) {3 R
24 $ \# i+ B. f2 G; ~. G
25 len = atoi(argv[2]); P! O! r9 v' `+ w
26 prio = atoi(argv[3]);
. u8 B2 ]5 U# r p+ W27 ' p9 P9 ]+ p( T/ @: g" A
28 //只写模式找开消息队列 , ~/ |9 L' a1 W) M3 N8 G1 X7 K
29 mqd = mq_open(argv[1], O_WRONLY);
; ^* U* r9 j7 ]30 if(-1 == mqd)
; s: @& |" o: N7 [/ T* U4 M31 { % ?3 S7 z/ b2 \# i/ o
32 perror("打开消息队列失败");
! k! Q" r1 U2 z1 P6 _) ~- B* ?33 exit(1); 2 d' H9 [; o- ?3 N8 t
34 } , J7 l& Y# i' p
35 / n& U+ h$ l$ N- n" R$ ^6 B
36 // 动态申请一块内存 ! T1 ?( K1 K) i/ t5 Y
37 ptr = (char *) calloc(len, sizeof(char));
1 A7 Z9 p8 n" ?8 f38 if(NULL == ptr) % q& \6 ^9 S9 a9 G
39 { ; J& x6 l: o5 _1 J' n _+ N
40 perror("申请内存失败"); 3 Z& o$ _0 l) m! Z& G
41 mq_close(mqd); E6 ?. O) X% d/ |! [0 a4 F5 o
42 exit(1);
3 B. T+ h) l; _ I4 \& I! E43 } 5 O. c1 d3 J1 t$ B
44
- B k* s& `9 ~8 W* \8 t45 /*向消息队列写入消息,如消息队列满则阻塞,直到消息队列有空闲时再写入*/ & r& e- X2 S) h0 d2 Q" N! a- F
46 rc = mq_send(mqd, ptr, len, prio); ; N% V8 }! |( I) X: s
47 if(rc < 0)
8 I' ^9 ~$ `! p48 {
1 w3 j K0 T0 z+ T+ |+ A5 n! G49 perror("写入消息队列失败");
1 g% {( {; y! ^0 y7 K50 mq_close(mqd); ! @& z: M& k) {; Z$ Y/ N# ?
51 exit(1);
1 {* B0 C: X6 E8 b52 }
! s& T0 s! ^- E- _53 ' n$ y5 B$ w4 M L% l1 s
54 // 释放内存 " t$ _9 i3 C) f7 H& X& E. ]
55 free(ptr);
9 V' q8 C* J+ q2 y5 F) o Q56 return 0;
: K, D8 N6 |3 R57 }
) Q Q7 U$ m. P, `
# v7 _0 n$ [* f$ k3 D. D' Q! l) ]& o
5 v$ u/ R1 S' ^- F* T& L编译并执行:+ N. C0 l/ I6 u' I
) a1 B/ s- `; @4 I4 j. F3 X
1 root@linux:/mnt/hgfs/C_libary# gcc -o sendmq sendmq.c -lrt# j: |- P' r. b `* e3 K' }' G
2 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 15
: I5 r1 z' j5 z3 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 16& K# L* P! M" |: q$ X K
4 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 17
" u: s+ n0 |2 a' k: O7 y5 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 18
( z9 q4 D1 G- X: R1 b" R% ~- L
上面先后向消息队列“/tmp”写入了四条消息,因为先前创建的消息队列只允许存放3条消息,本次第四次写入时程序会阻塞。直到有另外进程从消息队列取走消息后本次写入才成功返回。: ~9 ?9 m, M+ Q( P
- u( z/ n5 n7 s3 W3 j7 f0 ?2 g, ^# F, s
+ t) \. r6 ~8 T" D* a
读消息队列:
- g3 Q" A; N0 S/ z5 P c; G( F' `% t0 d$ ^* L* z
#include <stdio.h>
( x9 {0 D9 `+ n% d4 a6 X#include <stdlib.h>
+ I0 v' U( l4 E. E#include <mqueue.h>
: u* G% S" c$ q# A' X#include <sys/types.h> ! L9 p7 @' E. C
#include <sys/stat.h> 6 J* p/ ~* v" j2 j$ n- ~
#include <unistd.h> * f! ^; N5 n( d/ A
#include <fcntl.h> 6 @; n- h1 L a# c; B5 B) ]
#include <errno.h> * W/ B& a) h0 i& a9 }/ `2 U
/ {, W# e5 |# a+ h2 `0 w$ T, ~' w
/*读取某消息队列,消息队列名通过参数传递*/ 2 f/ v0 R4 S" \$ ]% u
int main(int argc, char *argv[])
' i- I1 \* ?' u) V7 N0 S2 T{ M+ V3 H' F! d( P
mqd_t mqd;
" V5 j% `: `& D( E5 x( C9 f struct mq_attr attr;
9 W2 ~4 M6 h) m3 E* ]* a5 S' d char *ptr; 2 a8 S- o- c' z! v
unsigned int prio;
2 F4 `$ w4 K: L: B( j; W- y M! ^ size_t n; - [% J% X X7 Z8 ?! ^, M9 q! D
int rc;
[( e0 J" a0 \3 o- q' o u# F, U, ]9 A( u$ V I
if(argc != 2) # w5 u4 b0 v: q& s$ u! O
{
( z( e& k: z k printf("Usage: readmq <name>\n");
2 r6 P- M( ~% z* \ exit(1);
% N, ?, D1 V8 C) Y( H2 I }
; _8 J% ~, ]' O, @/ V" n" D, U
: J B k' i0 p" f /*只读模式打开消息队列*/ 3 V7 U A/ j& a4 _6 D0 v7 O) x9 e
mqd = mq_open(argv[1], O_RDONLY); y# [( p, F- E7 q; F! d. v
if(mqd < 0)
% [2 H% x+ ?3 O& | { 4 f2 p0 j: I6 a' [
perror("打开消息队列失败");
5 ?8 I& o/ }* G R8 W exit(1);
8 `; V( F( h5 X$ u1 a }
4 [& E3 d2 i& K$ w- F
7 P4 `* t2 x1 ~# b, m // 取得消息队列属性,根据mq_msgsize动态申请内存
. z2 y; A* }) m rc = mq_getattr(mqd, &attr);
; h/ I$ U6 E# a! E; Q if(rc < 0) 8 X: K# C" Z1 T9 x" A0 B& A) W
{
F# m3 z) P: L2 m$ _) N# `& n perror("取得消息队列属性失败"); * M: w7 b/ y0 r" b) m
exit(1); 3 P+ C) H0 v) u# v
} % z. n# Z2 V% | O- e; u0 M( |
% C- S- b& I+ W1 a" o8 V$ y, d
/*动态申请保证能存放单条消息的内存*/ $ R$ u$ D" ]8 K+ h2 V
ptr = calloc(attr.mq_msgsize, sizeof(char)); ( _( `; R& L) I) h0 k( N4 {
if(NULL == ptr) / {2 b. {) Q1 E
{
! h4 @; _$ D3 S% m2 r printf("动态申请内存失败\n");
1 a! F# Z+ J! c' ? mq_close(mqd);
+ I" b! T# X i6 Z) U; N" ^ exit(1); ( n7 ^5 e G8 B* s' V4 s- a
} % g# x% |; v3 ^; U
) e4 Q% Z8 V$ {8 [: H+ X
/*接收一条消息*/ ) L; p6 ^9 J; ~6 z+ D& s: C0 {
n = mq_receive(mqd, ptr, attr.mq_msgsize, &prio);
0 u s8 ` k8 A# G1 A: a if(n < 0) # b; |3 I1 e8 M2 v
{
9 q; Q L! y* b6 l perror("读取失败"); : Z, b8 v% F# O& C7 d( U, r0 C1 p6 \
mq_close(mqd); 9 T, L) {# V) ^% _2 y' R1 j
free(ptr);
) B% g+ f7 P( B& ~5 k1 {( C exit(1);
. e" c. `& [$ M6 J% g4 _. a } 1 J2 r, X2 ]$ Y' Y
+ _0 x; T; {- Z1 ^: q$ Y7 Q
printf("读取 %ld 字节\n 优先级为 %u\n", (long)n, prio); ! l! n0 `6 P6 R1 N! t, ]: @
return 0; " K! H" ~* p% y
}
5 e+ G8 I6 ]% V! j0 d
+ t. s/ o$ O1 K; o. p/ d0 F" z, G! q# n9 r
& u c" Y" I# C& z0 Z8 b编译并执行:
& v0 t/ l/ ?* | X( H# V- S
) x' n& d1 U/ T, e2 v2 T 1 root@linux:/mnt/hgfs/C_libary# vi readmq.c
/ X$ N. `! N3 x; s 2 root@linux:/mnt/hgfs/C_libary# vi readmq.c
; `, G6 k) c% x( c' w" ` 3 root@linux:/mnt/hgfs/C_libary# gcc -o readmq readmq.c -lrt
$ L' k/ C0 j& g$ U: p 4 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp, M' T2 N7 C7 D/ V2 ^
5 读取 30 字节
; m+ L1 y! ]' f9 L 6 优先级为 188 k- q: z0 P. [
7 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
7 z2 \8 v2 y; ~" x: j1 }* V1 L4 Q 8 读取 30 字节/ d' A' j0 n* R4 c1 p, ]
9 优先级为 17+ A" t4 q% J) K0 R- ?! U( P
10 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp' o5 x) S' G1 O2 k
11 读取 30 字节( u! I! |$ ?! h! ]2 q0 y7 P
12 优先级为 16
. U. ~5 s( Z* Z& Z* L& \13 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp L9 r# \- }) Q
14 读取 30 字节2 x2 H; Y' W2 V
15 优先级为 15
! W; r$ v0 m, r( v% |( u5 g16 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
0 t* K$ A* @6 ^9 t! s5 r
6 g8 j0 i- k2 L, Z5 y/ X% U: h8 S3 D" D: Q Y3 N
) y8 i' T. w D' X
程序执行五次,第一次执行完,先前阻塞在写处的程序成功返回。第五次执行,因为消息队列已经为空,程序阻塞。直到另外的进程向消息队列写入一条消息。另外,还可以看出Posix消息队列每次读出的都是消息队列中优先级最高的消息。! D8 I2 f1 t' j" S
- z$ M' @( @0 n& z' p0 a
+ ?, E+ H" K0 e6 s( n5 s+ v0 D% M
2 ^1 T5 s* b i/ R: X; eIPC通信:Posix消息队列的属性设置
! h5 l3 m9 y1 {# ?: Z& Q5 F. [5 {1 c9 K4 X3 v8 I
- 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,若出错为-17 Y, ]# v, j6 y) f' V' r S% L9 S9 h4 L
/ ] z. A5 ~& Y# G3 v- X/ A$ o. T% K
程序获取和设置消息队列的默认属性:
9 }: C3 P* z6 a* Y" R6 ]
, f' Y5 h( Q8 e: `1 g! g0 n 1 #include <stdio.h> 9 l! }* n6 k& j& S4 \0 U0 Y
2 #include <stdlib.h>
% w" O P6 Z% i 3 #include <mqueue.h> 8 B% F. T* C1 b! }/ c" J! Y
4 #include <sys/types.h> D; i: h" X( \
5 #include <sys/stat.h> " t B' }9 G2 T7 _* a
6 #include <unistd.h> : n% G( B8 F! v$ {' h
7 #include <fcntl.h>
8 M! x; L+ V* V 8 #include <errno.h>
2 u5 p0 y% I( \ 9 8 V5 U. o- |# A# J6 s& d$ ^
10 #define MQ_NAME ("/tmp")
# x# W- a0 |0 l" y! } `11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag
. v: ], H0 W! F4 A* e. ]7 Z5 _, X) C12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限 * e, `$ \: R5 ^4 b+ n- n2 g& w
13 ! o) x! M0 X: o w/ r- a3 \
14 int main()
$ A( n- z6 D3 l5 Y6 |: _15 {
# `1 a' z s: ^% ?& D16 mqd_t posixmq;
; E# x; V9 }% \* y) D17 int rc = 0; $ T) S- p6 d e0 U% {4 f1 L3 J
18 3 a; i. D9 Q [
19 struct mq_attr mqattr; + k( r% u8 J1 I( d) r1 t/ N
20 " } I3 |3 U4 E: d
21 // 创建默认属性的消息队列
4 i3 @- u) i7 v" b0 z3 U& O22 posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);
7 G0 f5 M0 i$ v( J23 if(-1 == posixmq)
4 P, l }. |% M" p0 q( M24 {
# @" G; ]4 s6 A) c1 j; U25 perror("创建MQ失败");
( O+ P" X) U6 j1 ?26 exit(1); 6 Q/ h3 D2 W) j# b* f; d* ]
27 }
8 I: \3 o6 }' \% q; q& V f28 9 i2 D3 z" `& L2 ]. X
29 // 获取消息队列的默认属性
' n, N0 G; n9 h% m0 q" P30 rc = mq_getattr(posixmq, &mqattr);
' l2 I( F( R3 ^" Z9 _& t/ Y' J% v) @31 if(-1 == rc) ( o9 ^ G$ O* {# q! N
32 {
% @8 V4 R9 V/ p/ X* V& O33 perror("获取消息队列属性失败"); 8 V( _ ?/ y+ [+ m! P) `
34 exit(1);
# y7 A( K. B |# D3 e( ]: P35 } ; i1 T; |4 I2 H5 P( f* G
36
4 l7 R3 y, ~% q' i9 m, a37 printf("队列阻塞标志位:%ld\n", mqattr.mq_flags);
+ ~: T! X) @4 _, E' P8 S38 printf("队列允许最大消息数:%ld\n", mqattr.mq_maxmsg); 2 h0 s# a8 L/ U0 T0 c% }
39 printf("队列消息最大字节数:%ld\n", mqattr.mq_msgsize);
' ~6 i$ V3 b% X- m5 a0 b B; v40 printf("队列当前消息条数:%ld\n", mqattr.mq_curmsgs);
+ R+ X- ]& g0 P; c1 v+ a: k1 }41 2 K# v" A( j6 @" r* I
42 rc = mq_close(posixmq);
$ x, Z0 j" F' ~. h43 if(0 != rc) 7 B1 f5 `) ^% T4 g) Z: Y
44 { 1 k- v$ A1 F* c, d. R6 X; d# N
45 perror("关闭失败"); + A* n) {7 J$ }5 x5 p4 `/ N7 o \
46 exit(1); ' {# b) z6 b% i( Y l3 o. N
47 } ( t4 Z+ [+ h0 n' l. _8 d5 n
48
8 ?. [5 Y7 j( U. J+ b% [49 rc = mq_unlink(MQ_NAME);
( C# R" k) _7 o0 P" f+ w* i3 d50 if(0 != rc) 9 m7 N( G; f0 {7 c2 o8 e
51 {
; l$ [$ X6 j0 J/ A" w- M$ i52 perror("删除失败"); # t, B( T B: { w9 S
53 exit(1);
# f0 z, i* e C5 \3 E+ I54 }
2 n/ U: S& s. d( E# `8 T. w55 return 0; 7 O7 Y( Q O1 V: r* V8 W
56 }
% q9 C7 D5 f4 g, o5 K% Q* } ] q$ ~
2 l l3 S4 N3 c$ k$ ]2 Q# h3 j2 n {" x" z
编译并执行:
8 i8 a7 U- G. P; U L! k7 y) f; t' w
* Q0 F* U# `9 @: L5 s" S+ ~1 O1 root@linux:/mnt/hgfs/C_libary# gcc -o attrmq attrmq.c -lrt1 Q) T+ m9 a5 M& f& `2 k1 x9 b$ g
2 root@linux:/mnt/hgfs/C_libary# ./attrmq2 \( v3 l b6 J3 p9 _8 T5 L
3 队列阻塞标志位:0
' H5 s D8 q J0 J" c. s7 r4 队列允许最大消息数:10
( S2 y4 t0 L5 T2 M5 M* m* i5 队列消息最大字节数:8192
: c8 m. C: [! I6 U9 }* x" Q7 b6 队列当前消息条数:05 q9 a$ X" H. n2 G' d5 ~
7 root@linux:/mnt/hgfs/C_libary# 3 R( [: G a5 {4 S" P# B: \/ c6 m
% B6 h$ ?; p: k, m
0 {4 j2 w% h+ B* f设置消息队列的属性:
3 n; ^' |3 T3 @& ~
A6 K% H- M4 r) N- b$ |8 z 1 #include <stdio.h>
l/ ~4 S w6 b3 ?/ g" E 2 #include <stdlib.h> : p7 `5 z& ~. g+ [
3 #include <mqueue.h>
8 z( l+ G5 r2 r6 e. {9 | 4 #include <sys/types.h>
+ U8 b' A" N1 q+ f! I 5 #include <sys/stat.h> 7 `& D" h, S, I8 J1 r& H* W2 B
6 #include <unistd.h>
9 L) N; V. u9 }$ T0 ~ 7 #include <fcntl.h>
9 s! m3 v& |. _* ` 8 #include <errno.h>
1 B5 Q7 Y/ }0 ], k$ J 9 5 n) z% ~- U$ Y9 g% h' y: x" |4 n
10 #define MQ_NAME ("/tmp") ; ^' a' ?- E1 N0 q) g; k8 r: d
11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag # u8 ^+ ^7 P& ^0 J( o3 S
12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限 5 U( S$ Q7 \8 w. w. l% j
13 + t+ j! A4 z# r7 Y
14 int main()
* e/ z" r* l( X+ x: `/ ^ M15 { * B E$ R2 w! O* ~ P, a
16 mqd_t posixmq; 2 M" _& _ w4 L8 `5 ^
17 int rc = 0; ( M( Q8 b2 L5 M9 j g7 P
18
0 d* j, U* W# x) _3 M' v& n0 X8 N19 struct mq_attr mqattr;
- B/ |7 `2 `1 l) r/ k: i20 2 A6 d$ W: \: Q& m' X+ ?, f
21 // 创建默认属性的消息队列
) u$ w5 M% O9 y! p1 D5 u22 mqattr.mq_maxmsg = 5; // 注意不能超过系统最大限制
5 S+ W) O0 i0 M23 mqattr.mq_msgsize = 8192; , z0 \" U" h' H8 r. E& \
24 //posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL); - F0 R; k4 @+ O7 f
25 posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, &mqattr);
9 N# H0 N% B, Q2 Y! h26 3 @ X! I+ w2 b8 w; v8 j. ]
27 if(-1 == posixmq)
. n5 m' p0 Z+ v! U! a28 { ) ~0 v# L7 U& E$ v% `( k+ g0 }
29 perror("创建MQ失败");
7 L2 w$ e/ N2 s+ r" C, B# |30 exit(1); 9 `% E/ M. D9 Q0 s
31 } ( E/ c' Z L& h2 u( I3 p) g1 O
32
9 w; _& u& @. z& b' o33 mqattr.mq_flags = 0; 0 x; h, C- k3 T+ ?; d7 s" f
34 mq_setattr(posixmq, &mqattr, NULL);// mq_setattr()只关注mq_flags,adw ( k; v7 V& R: y
35 ) ~- ^5 c/ ]/ m3 h! N7 f
36 // 获取消息队列的属性
x3 z7 T% o; x& ^" ^; `37 rc = mq_getattr(posixmq, &mqattr);
/ b9 S; o9 n1 V. P u& @0 D38 if(-1 == rc)
( c' U, k; ~6 o' K$ O39 {
! }) }. }) ~* y. t/ c$ w6 E/ V' ]40 perror("获取消息队列属性失败"); / o9 a/ `# @( [# `8 L& O3 F+ `
41 exit(1); & G, k: }6 P4 k# J
42 } 6 S8 Z5 J1 T& a+ Y. o8 @# U% q* W; `
43
" k; F4 b4 g7 X3 H0 D# r44 printf("队列阻塞标志位:%ld\n", mqattr.mq_flags);
2 U* [( r' q7 K, l45 printf("队列允许最大消息数:%ld\n", mqattr.mq_maxmsg);
1 \3 q3 Q# F/ t( v8 }: u+ l46 printf("队列消息最大字节数:%ld\n", mqattr.mq_msgsize); % I! Z/ H# d$ T1 H1 k, }0 i1 _
47 printf("队列当前消息条数:%ld\n", mqattr.mq_curmsgs); / [( f; D8 @! p8 N
48 7 ]7 U& d L) ]3 P* n8 L
49 rc = mq_close(posixmq); * y; c5 {3 C; G) {' s
50 if(0 != rc) 7 o# A% `" g( m0 R% L
51 {
8 H& d' y. T& o a& a6 V7 V52 perror("关闭失败"); : O1 V1 E9 z N1 j. @0 L: `
53 exit(1);
$ o% X! Q& q* k0 v( z1 h54 } . O, j3 a) Z5 C' U3 X7 w
55
4 Z' t3 D J3 Z, N2 n1 `! x56 rc = mq_unlink(MQ_NAME); . a- Q' ]! u% e6 }0 r) S6 O m! V
57 if(0 != rc) + i' C, I! c! _/ ]5 ?3 B
58 {
4 H" L/ L( D$ f( I59 perror("删除失败");
1 N) x' }- M: d60 exit(1); 1 W& y1 B" j4 ` H* |" B2 B
61 }
3 n! ]9 s6 |5 h0 X- `) K62
7 s! \! ~& r, U) m. m63 return 0;
; \, W5 b" c, t64 } " a' [# v% n9 d0 B
# S% g$ h6 a/ A9 u) ~8 U
* d' c& f: d5 S" Q8 ]
编译运行:
( F( |+ F' v# m1 g+ h2 {3 ?+ j- |4 B% g" G# {3 j' }3 K
1 root@linux:/mnt/hgfs/C_libary# gcc -o setattrmq setattrmq.c -lrt
: R1 }8 Y) W+ M9 A( Q8 w2 root@linux:/mnt/hgfs/C_libary# ./setattrmq
$ a$ h g# F h' O( g- R9 e, C4 r3 队列阻塞标志位:0
7 a/ O) B: X# ~. w" n2 i4 队列允许最大消息数:56 ?5 Y6 o. V- K3 ?
5 队列消息最大字节数:8192
# P5 n8 p: B7 ^ _$ R; E6 队列当前消息条数:0
- H# T- j3 a$ W( J6 J) Q. @- o: o) B" i
$ U p9 c( e* Y
( P- Q) N2 K4 I0 {* i/ `! B/ ?* N* z% N* ~/ C
3 J5 {8 Q. ~: Z7 n( n2 a4 M/ k% Z5 P6 E' ~2 @! {
8 W- ~' b1 P$ k: s a* T4 F s2 B
5 b& ^* P* U6 y( O! k. E8 v& I- ?
% b3 P) X- R) ^5 l: ?
( h2 T( y, \& c: {$ y5 x3 O/ x0 W' J7 k) |% O2 F
|
|