EDA365电子论坛网

标题: IPC通信:Posix消息队列 [打印本页]

作者: mytomorrow    时间: 2021-4-26 17:10
标题: IPC通信:Posix消息队列

* R9 b* f( o! ^ 消息队列可以认为是一个链表。进程(线程)可以往里写消息,也可以从里面取出消息。一个进程可以往某个消息队列里写消息,然后终止,另一个进程随时可以从消息队列里取走这些消息。这里也说明了,消息队列具有随内核的持续性,也就是系统不重启,消息队列永久存在。; P, G$ U0 ^2 X. q% }9 S6 U- l

8 L% [1 C& o$ l6 o- g# A创建(并打开)、关闭、删除一个消息队列0 P  R: e" x* v- m4 X
5 v  ]3 j3 e& P6 J
1 #include <stdio.h>  . t" Z8 i5 D  J5 O+ C& q
2 #include <stdlib.h> . b1 l! d* s" s
3 #include <mqueue.h>   //头文件
1 ~& g+ a) x0 T5 r' q2 j0 n9 p 4 #include <sys/types.h>  : I9 r: v2 a5 D& u0 T! N3 ]6 x& m
5 #include <sys/stat.h>  
' ?* \: R- R  R 6 #include <unistd.h>  
$ D2 M  ~  }; f$ J. D% {  k 7 #include <fcntl.h>  
: B* @8 D* p6 E0 b% m7 O  J 8 #include <errno.h>   
+ ^8 W0 w9 y9 v- S, m; m 9 2 C% H, a# v2 \! M, l6 T
10 #define MQ_NAME ("/tmp")  
6 @# g/ J5 b+ v. C) l2 p+ G: e: r11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag  
& G3 X9 U( S, B% ~& P+ F12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限  + {9 e( D7 }6 G" P( E  D
13
. V% H9 e2 d3 i3 L8 k/ L9 [) w. W14 int main()  , l5 X" Y- ?' ~, w' o: {
15
! B- N4 H$ }2 |3 \- W& u% d- m  m16 {  . z0 ^2 R2 V0 Y/ i1 e5 `! @
17     mqd_t posixmq;  
$ {0 D! q0 R( J  o* L18     int rc = 0;  
$ j8 R2 V7 H: K+ s. u7 @19 / |& E" g6 f* s* A4 Y+ P
20     /*  9 L7 L8 |2 u5 x7 v& B& Z
21     函数说明:函数创建或打开一个消息队列  
9 g) ?; Z/ s. E! b) ^- y  }22     返回值:成功返回消息队列描述符,失败返回-1,错误原因存于errno中  
: u8 C1 i: i- u$ |6 \0 d4 J4 O23     */ 1 b" e. H: V6 I) \- Q. a4 o
24     posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);  : V2 v' u! U) J- @6 m; m
25
6 N# a6 G3 l' X# p- d8 _$ [- H9 r5 ^26     if(-1 == posixmq)  - @% W4 o  X- Y% k3 s! s+ `; P
27     {  2 l! @! t; n) Q
28         perror("创建MQ失败");    P$ ~0 T. T0 R5 n/ d0 e1 W3 |: o
29         exit(1);  
8 V9 M% s6 a- Q' Y, f, s30     }  
5 ^: ]% f8 x  A31   }# l% v: k" o
32     /*  
" \. Z* }; ]3 X+ W$ j/ P33     函数说明:关闭一个打开的消息队列,表示本进程不再对该消息队列读写  
# G& e  x' O/ z34     返回值:成功返回0,失败返回-1,错误原因存于errno中  , z! A# ^7 M0 w8 P
35     */ + y$ [* k4 I; O! v' R# E
36     rc = mq_close(posixmq);  
) \" a% G# b* T1 Q& w/ G37     if(0 != rc)  
- M3 y5 F: }4 B$ z: p, k9 n38     {  3 O2 h, T, {0 a9 a" F3 ^
39         perror("关闭失败");  
: q# Q' H- `7 H4 u' g40         exit(1);  
' Y* C) r0 S  p' |41     }  
9 [4 Z, j5 M3 A' c6 ~% _42 " s/ v: K+ N7 h6 ^
43     /*  ) r: i3 F1 }& l/ @1 O: ^
44     函数说明:删除一个消息队列,好比删除一个文件,其他进程再也无法访问  
) b: Q- h. O# E- p( k! q45     返回值:成功返回0,失败返回-1,错误原因存于errno中  
/ s4 s% I+ H6 w6 i+ W+ l46     */* E- I2 i: i0 C" ]# W2 @
47     rc = mq_unlink(MQ_NAME);  
: Q- _8 C0 m0 h! Q/ o% d48     if(0 != rc)  
7 o; ?. _" G: E" r) [! d6 \3 G49     {  
7 L9 J0 _, i' G$ z50         perror("删除失败");  , H3 e/ V) x- c7 B
51         exit(1);  
2 q6 c- L& i/ o! I' ?; M52     }  
5 L$ l' ^. t" p3 J53
8 X  }; Z; `9 K+ u54     return 0;  1 N! Z7 ~' O; N% m! \' C
55 }
- D/ F1 U4 B% X1 E" U
3 {( M) ?0 Z8 t- l  W4 G" k- n: H
) S: @9 _( |2 w编译并执行:
" d/ \, X/ R! m" ?. n
8 m/ I( a  D) U4 O 1 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c- f0 E' s! j) E- K( t' ^6 T' A
2 /tmp/ccZ9cTxo.o: In function `main':
1 t) {% F& f8 |- ~! H( c; s 3 crtmq.c:(.text+0x31): undefined reference to `mq_open'5 k( l; {  G5 {; {$ Q; U4 v& k
4 crtmq.c:(.text+0x60): undefined reference to `mq_close'. E( `  z- R, V4 H3 J
5 crtmq.c:(.text+0x8f): undefined reference to `mq_unlink'
4 v. T( P- N4 ~ 6 collect2: ld returned 1 exit status8 L1 |+ l' O( [6 x1 R7 C8 k: F
7 因为mq_XXX()函数不是标准库函数,链接时需要指定;库-lrt;
- b6 J3 J& ^( f1 b. O 8 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c -lrt6 }0 I; F# F6 G! O& j
9 * P7 @, `( r# e$ T
10 root@linux:/mnt/hgfs/C_libary# ./crtmq
( q# _. k$ S9 t, J% t* Q; @11 最后程序并没有删除消息队列(消息队列有随内核持续性),如再次执行该程序则会给出错误信息:
6 A$ U8 @  J0 i7 p, R, g12 root@linux:/mnt/hgfs/C_libary# ./crtmq
$ S& H( h, [/ s13 创建MQ失败: File  exit(0)
3 ]3 s# k# n$ c& O" X$ U% m( Y) E/ @/ W  n" [

7 E$ h9 v- j; w2 H3 w3 p! B' [3 `4 S' b0 K( r
编译这个程序需要注意几点:
. h+ a  H( l' ~1 [4 i6 B8 k
5 U8 H6 G- ~! r3 d; k  \; H9 b1、消息队列的名字最好使用“/”打头,并且只有一个“/”的名字。否则可能出现移植性问题;(还需保证在根目录有写权限,为了方便我在root权限下测试)
8 b2 y+ C8 h: e; ~* Q$ S) Q' j2、创建成功的消息队列不一定能看到,使用一些方法也可以看到,本文不做介绍;
. _. @7 H: ?" e( r( L3 z
4 u9 `& f& n$ z2 {& |$ G2 l  消息队列的名字有如此规定,引用《UNIX网络编程 卷2》的相关描述: mq_open,sem_open,shm_open这三个函数的第一个参数是
& O4 b1 i4 N$ |一个IPC名字,它可能是某个文件系统中的一个真正存在的路径名,也可能不是。Posix.1是这样描述Posix IPC名字的。
6 |6 ]: p2 B9 ^+ Z$ }% J1 q1)它必须符合已有的路径名规则(最多由PATH_MAX个字节构成,包括结尾的空字节)
# [3 ?4 x  e* l0 J" t" H/ f2)如果它以斜杠开头,那么对这些函数的不同调用将访问同一个队列,否则效果取决于实现(也就是效果没有标准化)
8 d1 \! o# J' k; z" [8 B6 f; U5 @3)名字中的额外的斜杠符的解释由实现定义(同样是没有标准化) 因此,为便于移植起见,Posix IPC名字必须以一个斜杠打头,并且不能再包含任何其他斜杠符。) H# e# R, o8 G$ r
" S% R& V! f5 S' ~0 f& I( O

  c' q1 ]* K- o; yIPC通信:Posix消息队列读,写
6 y9 u# t3 Z* F& [
0 L; S' h8 G" ]4 ]3 ^! ~7 n创建消息队列的程序:$ l; V- @: ]+ i# Q9 A% B& l) M5 D
+ l* j' ?; ~. O# E* {
1 #include <stdio.h>  
+ k9 z: W3 a9 w  W7 Q" F 2 #include <stdlib.h> 9 H3 O( k  s  X
3 #include <mqueue.h>   //头文件
" N6 P3 v2 {; f5 Y2 m, q 4 #include <sys/types.h>  
( N' G' D+ D% W# a! ^ 5 #include <sys/stat.h>  
5 n& i4 {1 x8 ]- X9 Y4 ^5 \ 6 #include <unistd.h>  
, |4 B7 w" y, S8 L 7 #include <fcntl.h>  
; n1 ?8 R! W* }. l" s9 J 8 #include <errno.h>   " ^, @% R0 h: q8 R" r( j5 g0 n
9
* v) Y$ L  k. {. U4 N10 #define MQ_NAME ("/tmp")  & P6 ]+ E  L! k' ]  ?# R
11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag  
* \+ J8 M$ m1 ]12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限  6 G* I6 g4 e. ]3 N# p7 U. l4 w
13 0 b. P- y2 n! d, m
14 int main()  
5 @; H4 ~3 I# [+ C. o. S$ a7 [15 8 e1 u& p) ]& r- o2 S  M( o
16 {    w8 T! F+ @: E" A% O
17     mqd_t posixmq;  
8 D& v  f$ [; s1 p: e5 J! G18     int rc = 0;  
% @8 d* `% t0 @8 p19
3 n. Q5 S" i$ P  S0 m- O20     /*  
! o, `* p5 C9 H+ O3 ?+ D/ v21     函数说明:函数创建或打开一个消息队列  6 p) }5 }1 c( j& D9 v  W! u2 T
22     返回值:成功返回消息队列描述符,失败返回-1,错误原因存于errno中  & g* H! E+ I6 k' u, C4 {
23     */
3 Q4 i! _7 T) h& e24     posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);  1 F+ i6 A- A2 `5 p7 D
25 / ^- k+ x; |2 V& ?8 Z9 d7 l
26     if(-1 == posixmq)  7 C; F" g' s3 O. J. k
27     {  
1 P& `1 m9 C& r" C* y) L28         perror("创建MQ失败");  ( B1 d8 m) l! o: `0 B
29         exit(1);  
+ m3 C9 S9 ]) ?  C: a. P30     }  % a# f9 \% y0 D( X; P4 V
31 ' j0 p& Y0 M8 I$ S! b
32     /*  1 e/ W% b* g# \+ [
33     函数说明:关闭一个打开的消息队列,表示本进程不再对该消息队列读写  / g! B, `9 R4 ~
34     返回值:成功返回0,失败返回-1,错误原因存于errno中  
+ j; I2 N2 f+ _5 t! |! K35     */
* r8 }8 a7 d/ r' b" G8 d# j36     rc = mq_close(posixmq);  
; e+ K9 E0 h% l5 Z; ~- i. p, o6 e37     if(0 != rc)  
: D; x/ L% g+ d4 p3 r8 w38     {  
- R: B* r* o$ n! U" H9 O2 c, f39         perror("关闭失败");  
" k; H) I! i6 W/ Z, M40         exit(1);  
, t" X  k* S: }& h' F. }41     }  
$ L) b5 }9 C7 M5 T  ^, Z. i42
  W) q5 p( g+ S4 [# a$ T43 #if 01 G+ u" \$ z1 ^! s: `
44     /*  5 p4 }0 y5 @8 m
45     函数说明:删除一个消息队列,好比删除一个文件,其他进程再也无法访问  
8 n/ A0 F1 c, E9 A  A0 {) O. g7 N* M46     返回值:成功返回0,失败返回-1,错误原因存于errno中  % B& x' o/ T: D# }0 a3 c6 T. E
47     */" B* U  D& x3 Q& ^; b3 z! h
48     rc = mq_unlink(MQ_NAME);  # ?6 Z% g/ K+ ^9 ]
49     if(0 != rc)  
$ z/ p* R# F: [/ k5 b( t5 i. @50     {  
0 {0 w% G, I, c& Z51         perror("删除失败");  & w  Z6 ]$ p" Q/ m# U
52         exit(1);  6 t. V! p$ J( K. d
53     }  0 j4 }& g" l, i/ t
54 6 C" b3 u. `! ~5 P: B4 [( F
55     return 0;! l0 x7 U! l4 C* Q7 u% q" t4 p
56 #endif  2 U- J7 Q5 b' [1 C; P' s5 Z8 n
57 } 7 k! T1 x' V, n) }4 O5 x
0 _: j: @9 ]* B4 P  R
& o! J8 e( r6 a) b4 Q% r2 \' r8 |
" H2 p, Z+ k8 f- S( Q
编译并执行:
% X! k. v! W8 w/ {( E7 p, I) T
1 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c -lrt
$ e1 |5 P* z3 v; s. i2 root@linux:/mnt/hgfs/C_libary# ./crtmq
- h$ K! c9 a" Y9 O- s) `- q, E3 程序并没有删除消息队列(消息队列有随内核持续性),如再次执行该程序则会给出错误信息:
# h& R) w+ Z* z; S. V! B4 root@linux:/mnt/hgfs/C_libary# ./crtmq
: R9 r% n) A* F( a. x# g- y* \7 n5 创建MQ失败: File  exit(0)* D! F% ], \6 O; `  P
* S9 D3 D3 @$ k' ?( m  B

$ s6 \; Y! C# V7 ]向消息队列写消息的程序:
, h1 L# E8 D, D# F% M0 w, N
) S3 r: \8 o0 v- D3 e! r# o4 n, c% P! [, y4 Q: n8 V
& U. d4 f- V* l" L

, P) j, u, a4 @8 U. M' Z  C$ n$ z! E% z6 i' \( |5 a- ]
  c- z8 u8 w, R4 a1 L  k# J1 F
1 #include <stdio.h>  . V2 a) c! V" V' W
2 #include <stdlib.h>  * m9 \  T- W- ]- ?9 g  I' B
3 #include <mqueue.h>  & u/ d* B$ P: a: k2 p% [6 [
4 #include <sys/types.h>  7 h6 U- n4 I( e' q* e
5 #include <sys/stat.h>  
" _; h3 A2 n$ q9 I) t$ h 6 #include <unistd.h>  $ c$ n0 U/ N2 w* u) z% D3 J
7 #include <fcntl.h>  
0 Y: P, X' T1 F( U0 g, T' ] 8 #include <errno.h>    o: e- R+ {; L5 ?) Q7 ~+ M
9      X- ^& c4 w$ ^, u) A. a0 v
10 /*向消息队列发送消息,消息队列名及发送的信息通过参数传递*/
9 s: }! w. F+ r% J11 int main(int argc, char *argv[])  2 a& r0 Y$ c6 R
12 {  7 ?  ^) J9 |; u7 {" d
13     mqd_t mqd;  
& v7 O, X( M' E6 {2 A7 h$ z14     char *ptr;  
* M2 h( H9 C8 F; ~& ^6 J- m15     size_t len;  & m4 @0 r/ z9 P5 P9 b: z
16     unsigned int prio;  
3 H9 B! J, C2 E) e% B  Q17     int rc;  ( u: Z, O5 ~) v! F( J
18 / k3 n5 D  }1 S; K6 p8 M1 ^' Z$ }
19     if(argc != 4)  
2 p5 K$ Y1 ~9 g' U& ~3 Q4 D. d20     {  
' L: |: H/ Z0 m; b: f1 ^' @* V  ?+ o# X5 W21         printf("Usage: sendmq <name> <bytes> <priority>\n");  
% V1 n) K0 k9 [7 b, Q, k22         exit(1);  
; P7 ~+ `( W. W! p; S+ O! E: F23     }  9 c( }1 p3 y% i
24 9 r  W% V* k2 Z' H; \
25     len = atoi(argv[2]);  
* q/ s/ }  O+ a0 H& W26     prio = atoi(argv[3]);      I; }- h/ S" i8 Z& X" X$ [
27 , T; t+ `- t3 ?/ f
28     //只写模式找开消息队列  
5 e- A) O: U: S0 u0 V0 U29     mqd = mq_open(argv[1], O_WRONLY);  
" P& m( f% v) {) |* Q/ E3 n30     if(-1 == mqd)  
, X8 ^, |+ Q1 G1 I31     {  / H" f0 x& B: A3 [, g; p3 l
32         perror("打开消息队列失败");  # S. T  {' ?  O
33         exit(1);  
( }' n4 q' `7 h& b3 H+ m' U34     }  
1 T3 t9 j5 X% c+ R' W35 2 U; z( W% V  S- |' K
36     // 动态申请一块内存  
. V- J  S' A) V37     ptr = (char *) calloc(len, sizeof(char));  5 O! t* p' l+ C! o3 O
38     if(NULL == ptr)  
. ]1 K: m8 b. ^  U. J, n; _4 I; ?39     {  
+ r* n! j" S8 Q40         perror("申请内存失败");  % K0 W/ _: F& y+ P6 Y1 B6 e
41         mq_close(mqd);  8 j& S2 @4 ?) y* H6 _
42         exit(1);  
8 t0 [( b, ?. C" ]& ?7 Q/ A43     }  
: P5 Z" q& o# \44   
5 E$ Q/ O3 \3 f5 z45     /*向消息队列写入消息,如消息队列满则阻塞,直到消息队列有空闲时再写入*/ 1 o6 N. I" o, g0 P$ w/ K5 m7 l
46     rc = mq_send(mqd, ptr, len, prio);  . C6 V; u8 m1 C0 X1 m+ v# u+ T3 E
47     if(rc < 0)  : e7 ?, ^% _7 o3 t) |, ^! q
48     {  
1 I2 ^2 E" N% S: t& |( b& \49         perror("写入消息队列失败");  
5 F; ~# ?0 g/ Q# _! g0 d7 ?50         mq_close(mqd);  
4 {3 g  ?1 b9 \9 f" t: k51         exit(1);  
4 O6 Q/ y9 a: W52     }     
* C* @" K6 `7 _( G' V' j! b1 f53 2 o, ^1 V! Y4 N; L  E& Y3 A
54     // 释放内存  
2 i5 W+ m. _8 q/ f" y55     free(ptr);  
; t4 S9 a1 e, H& s8 z1 C56     return 0;  ; u0 q; [$ Z9 Q: ?( T
57 } . k9 C4 I7 L* k# X0 Y4 s; T4 Z

+ a+ r5 o: o" @% q  p* T' H( A) E  T
编译并执行:! o0 ]" _9 q) [
0 ^/ d9 O- I) r+ q6 d' d- F, I% r3 p
1 root@linux:/mnt/hgfs/C_libary# gcc -o sendmq sendmq.c -lrt2 \& c% C  E# R" z. V8 d. Y
2 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 15
; ]6 _  c& Q( q( m3 }8 x3 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 16- z/ W9 }+ J8 B
4 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 17" Z* q& _( S% p1 Q4 p  J3 g
5 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 18
* G% D7 {/ I, h3 R; ?& k  [+ S4 |! n
  上面先后向消息队列“/tmp”写入了四条消息,因为先前创建的消息队列只允许存放3条消息,本次第四次写入时程序会阻塞。直到有另外进程从消息队列取走消息后本次写入才成功返回。
6 b- }$ P( X5 _; `$ h
3 Q& C. t% j- A/ [  N! k8 I! B1 b! Y4 Q; u
) ?! H5 F" ?  C/ g
读消息队列:
% i: t0 ^- o% W# ^  I; `0 K& j4 s3 T
#include <stdio.h>  ) M( E; Z" K( g  u  g- y! P
#include <stdlib.h>  
& j; g. ^! P+ t" R& T3 K#include <mqueue.h>  
" m1 N& D7 R; i7 c" B7 Y#include <sys/types.h>  
. z3 u9 `8 O' {: n8 [#include <sys/stat.h>  
, {9 c* y! X& k; F3 ^, m#include <unistd.h>  4 [* G, }! l$ R6 D* Q8 P6 n
#include <fcntl.h>  8 i# H% J4 O3 Q4 @+ |
#include <errno.h>  * b" L9 |: u/ s

8 g2 O" [4 V7 i2 X/*读取某消息队列,消息队列名通过参数传递*/ 7 y3 g; M) ?: f* t
int main(int argc, char *argv[])  # U4 r) G' h, C
{  
+ {3 o! u- |! f4 o& _    mqd_t mqd;  
3 y% @0 h6 y+ F: X2 ?    struct mq_attr attr;  
! q* c6 f; H  ^$ k) l0 [( J    char *ptr;  / T+ l1 w- a" u) i& e) D4 V+ p
    unsigned int prio;  $ I+ P5 |9 W1 \9 s1 Q
    size_t n;  ' r+ q6 |4 \" Q/ ?# I0 l
    int rc;  ' Z  ~6 h4 r3 i2 a7 \& F
0 O+ z3 P# d4 R
    if(argc != 2)  
. b) Y, R: b" k0 n1 M    {  + K4 o: b& s' ~5 ?8 k5 M
        printf("Usage: readmq <name>\n");  
# u& `- B; n$ p# H$ M2 @        exit(1);  
3 E  g3 k& x. r8 T9 C+ n2 u( A) i$ |    }  ! d. d& V6 Q5 m2 p/ ]1 A% ?: {

5 M' n, B. \' c) h9 b! Y  y    /*只读模式打开消息队列*/
6 R' w3 F( Z6 b4 Z    mqd = mq_open(argv[1], O_RDONLY);  
' b. i5 Y7 U9 v  T" E    if(mqd < 0)  
* c5 R+ c0 y/ @+ x    {  
% k0 R; ~% x0 e( B        perror("打开消息队列失败");  : n9 w! u0 R  k5 W  u* k
        exit(1);  0 ^$ r5 j* w' s, t6 A+ h
    }     
% M  C7 D$ a/ o& }% {7 D4 `. \6 @
0 O8 R- U' E! \$ [& V( M    // 取得消息队列属性,根据mq_msgsize动态申请内存  - w. b9 Q$ Q! o% J( T
    rc = mq_getattr(mqd, &attr);  7 N% Y. {  k2 Z0 ~
    if(rc < 0)  * m6 |/ k+ H' `$ @! o. D) E. p. I
    {  * m' Q7 f6 p1 I
        perror("取得消息队列属性失败");    g7 z" o. Q1 h9 }/ q- b
        exit(1);  * o5 f4 A4 E+ a" |
    }  
. g' ^6 n, L) O! E: E. n
# z$ _' |* A* J, @+ ^0 d    /*动态申请保证能存放单条消息的内存*/ $ ^  @* {' A( I3 ]1 L7 N
    ptr = calloc(attr.mq_msgsize, sizeof(char));  
! Q1 f$ n) m# _! Z3 @7 J    if(NULL == ptr)  & N  @( Y' p( Q# Q) x" {
    {  ) `# {, _+ {0 a. G/ ]! {; r; u
        printf("动态申请内存失败\n");  
; j6 D" ]1 {' p9 E: a+ i        mq_close(mqd);  
, g; T& ?0 i2 j/ _+ @8 j3 V  A: k        exit(1);  
1 ?7 d# o7 d5 @) O7 p0 O- E* A    }     $ p, l9 D. w  c+ L
) v0 \3 K' E- K# s4 _
    /*接收一条消息*/
( [6 k' z+ C  k    n = mq_receive(mqd, ptr, attr.mq_msgsize, &prio);  $ T$ }! Q% ?: u! \
    if(n < 0)  + V" P% b( Q. \5 W, E: }
    {  % R; X6 x" F9 X; v1 r2 S2 {
        perror("读取失败");  ' [( x1 U3 c8 d( M
        mq_close(mqd);  * ?0 j% g0 b8 s4 G
        free(ptr);  , v) |% z7 Z' w3 U
        exit(1);  4 ^7 r/ `) v% N8 ~
    }  1 {' Y2 v6 ^- l2 Z: @9 o
      [$ y& w% _" K1 `9 \
    printf("读取 %ld 字节\n  优先级为 %u\n", (long)n, prio);     + }/ |5 @" G- _9 A$ d
    return 0;  
1 W; v8 r) O+ v} / t' j9 y: t! {9 a/ X8 E* q# h$ Q

* e, w$ S) j- ?0 q; W3 k' h+ y+ l9 O* v* b* C7 T- q1 s! @
6 Z( k1 B3 J; b
编译并执行:
$ s+ Z$ _5 i) m( _$ \9 ~
# E- o$ t4 k0 y 1 root@linux:/mnt/hgfs/C_libary# vi readmq.c( l1 t8 |( W$ i- O/ Y' [. f& q
2 root@linux:/mnt/hgfs/C_libary# vi readmq.c* v  Y( W$ i. g1 ?
3 root@linux:/mnt/hgfs/C_libary# gcc -o readmq readmq.c -lrt5 `; d( M  u. c& P
4 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp( F8 H- M1 y& Q3 M* W
5 读取 30 字节2 M9 B  }! V4 O. h5 y- C
6   优先级为 18' I6 a/ t# x  G4 V$ w9 k0 f: r9 V
7 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp6 y: I+ B, L$ I4 N+ a  a
8 读取 30 字节
5 t. v$ Y2 p1 ^3 Y* |% o 9   优先级为 17
% Y) B0 Y* f  K* m# P10 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp; |2 P  M' Z* d2 z
11 读取 30 字节% z2 [2 z- h0 ]9 P" T8 F, U: I$ |
12   优先级为 160 L7 [. C4 z$ I2 y1 ^1 W$ F
13 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
4 o3 [0 y- t5 t( T! c/ h+ B14 读取 30 字节' {' D8 Q' ?5 E( s8 H. a/ o
15     优先级为 15
8 Y6 b0 e3 |" c16 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
9 r3 K. n! {/ |" n$ J1 t% B, H, @* S. z- g$ O* o' K

6 Z% M  I2 H! P# m- q# P) }1 x5 O6 i3 h* r5 g- n2 N2 @
  程序执行五次,第一次执行完,先前阻塞在写处的程序成功返回。第五次执行,因为消息队列已经为空,程序阻塞。直到另外的进程向消息队列写入一条消息。另外,还可以看出Posix消息队列每次读出的都是消息队列中优先级最高的消息。
# B" D9 G, p- j" n# }. a" V. T+ }' r: L2 X' V
; G8 b, @7 m* y7 Y3 d
/ u5 v* m7 Z/ T
IPC通信:Posix消息队列的属性设置1 T3 {" t5 D  O. v( o" ^/ C
! G6 V+ d7 t8 }2 v* q+ D/ G

1 y0 R# E8 Q/ R% ]9 Q8 A
+ u( z$ E9 O! l( U程序获取和设置消息队列的默认属性:- P8 C; e2 \. v. A* o4 a) V

8 g! f& x, G; J; m4 i% a/ O 1 #include <stdio.h>  
+ W6 W, a$ [: B4 l 2 #include <stdlib.h>  
; m0 V: B5 |0 a8 \ 3 #include <mqueue.h>  " z. @9 _% f, {
4 #include <sys/types.h>  ! a/ S1 {  J  C
5 #include <sys/stat.h>    B( Q+ N$ t1 F& v
6 #include <unistd.h>  4 u2 `: e! {3 ]
7 #include <fcntl.h>  6 h, X2 v. Q7 {+ p4 m
8 #include <errno.h>  
+ o* H; b0 v, c7 K. n- V7 W 9    2 ]4 n) B4 ~( l$ k3 F
10 #define MQ_NAME ("/tmp")  5 {- o  g- |  \; S
11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag  
, d! r) A. \" c5 f12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限  : Y4 W( c# T) ?& d' Y' O
13    # z) G" `+ E, E3 Z; k7 m: s
14 int main()  
7 R& h, T  n+ x! n- N15 {  & h  ?0 b/ Y" B9 \: R
16     mqd_t posixmq;  
9 b) Q5 c  {0 f2 [( `" Y- h. [& a' h17     int rc = 0;  
1 [6 P. q* \% ]" |18    - y' C- m, W) s" `$ r  G9 f
19     struct mq_attr mqattr;  ! h7 [4 u# @, l, H+ E5 e2 H9 m
20   
* |) n# x) u& f" i6 S2 V, }  P21     // 创建默认属性的消息队列  
$ J8 Z' w0 W0 n8 f* l5 X! F- H( B22     posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);  
% s- D4 B+ w6 O23     if(-1 == posixmq)  $ }; i( @" ^' Q) w" c
24     {  0 S2 L5 W# S" F: H5 m
25         perror("创建MQ失败");  : _8 N+ s" W' J$ q6 o) ^2 O
26         exit(1);    n$ U% m1 i6 H) D
27     }  # I. @' F; j4 p
28        
7 X4 Y. O% Q6 o  _0 u29     // 获取消息队列的默认属性  - `. o8 O+ C) ?
30     rc = mq_getattr(posixmq, &mqattr);  . {* w3 G; @& c8 N# Q$ S
31     if(-1 == rc)  
" D5 T  e, n" J0 k/ }32     {  6 Q6 U) `' S; F1 S& K( Z( f+ J
33         perror("获取消息队列属性失败");  * Y+ ^; C; k- j: A) D
34         exit(1);  
  `* j# L$ F2 p& t1 [! q' k35     }  1 x+ e5 |5 |4 l; A* i: s0 C) E
36
$ {" T0 F2 I8 z& O( K0 t5 c37     printf("队列阻塞标志位:%ld\n", mqattr.mq_flags);  
- D9 Z4 e) w9 b! Z! |9 e38     printf("队列允许最大消息数:%ld\n", mqattr.mq_maxmsg);  
# R( i: P- _& T. Z39     printf("队列消息最大字节数:%ld\n", mqattr.mq_msgsize);  2 [3 X5 z9 s' G4 q" x1 A; O
40     printf("队列当前消息条数:%ld\n", mqattr.mq_curmsgs);  
2 E9 M: V; g2 S3 m8 w41   
% E- V1 [" ~% w42     rc = mq_close(posixmq);  * K' z, S9 q- N& g: C  Y
43     if(0 != rc)  * \4 ]; X# X; S( c( r+ F
44     {  % l% A# H6 M/ a, ?
45         perror("关闭失败");  
" z/ v& k9 G( T46         exit(1);  " V. |0 |  M) G, @
47     }  
7 ]. _. Y, s/ j- d, n/ n( C. ?48   
6 E5 ^. f  E" u0 V6 W. D49     rc = mq_unlink(MQ_NAME);  8 o  P9 E$ J4 Y% t- C+ L( k- q& N; W
50     if(0 != rc)  
6 d9 U( p3 h+ w4 Q* r! h' c51     {  
/ ^/ v' J: q* k- O" W$ }  X52         perror("删除失败");  
7 \; j6 q8 J, z$ r( _. Y& W53         exit(1);  ' ?. n# @7 v6 v1 }) o* q) y
54     }     % k% K( T" q: k& L  I
55     return 0;  : c5 `3 K' E# M- |) I; |; @( ^
56 }
- r- o7 ~1 f& d  d/ W- j- c9 q/ x
6 h$ l: s3 @$ P
) ]& _' S. ?2 ~  ~& R编译并执行:4 a) G9 g( X; O0 M& N

+ \" V3 ?7 O# r/ {. U6 E1 root@linux:/mnt/hgfs/C_libary# gcc -o attrmq attrmq.c -lrt
% c& T# g9 e$ d" E% h) V4 C2 root@linux:/mnt/hgfs/C_libary# ./attrmq
) c- j! h7 a1 I1 i3 队列阻塞标志位:0( C7 g0 f2 o2 x
4 队列允许最大消息数:10. o" W" u! I+ c! F$ K: q
5 队列消息最大字节数:8192$ B4 ]7 n/ @3 n" v' a, `
6 队列当前消息条数:0. l4 x4 @& I/ B
7 root@linux:/mnt/hgfs/C_libary#
+ r- L" O. ?8 S
& i8 B* w7 q  s$ M% M6 Y5 V
' S, o6 w6 \% m# s1 V  m设置消息队列的属性:% q" }- D# D) V
( o0 M( I+ V3 k/ [
1 #include <stdio.h>  , ~! |, ~  Q* [& h& \  q
2 #include <stdlib.h>  
! ~8 v% s1 \" Z# U7 z& { 3 #include <mqueue.h>  
. R$ u% g5 l9 @  i) n 4 #include <sys/types.h>  
* p  c1 P7 T0 i% |' n/ R1 w 5 #include <sys/stat.h>  
7 q/ L6 C) ^* @3 Q3 b) p( C 6 #include <unistd.h>  
- z0 j, h, |3 a5 q7 j2 z 7 #include <fcntl.h>  
: C7 ^" {( G+ h 8 #include <errno.h>  
9 G) ?9 j) Q) j 9   
9 p- ~5 ^3 V/ H1 e8 c9 [10 #define MQ_NAME ("/tmp")  $ e% }, s; `; g: z( k" ?% `9 k
11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag  
& J) @2 m! v- g- i; M2 [12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限  ' p9 m( Q' N: E6 E6 s/ n
13   
- N$ u3 o0 W% l$ L/ Y6 K% m5 h$ P/ i14 int main()  
6 O! M# M/ t9 s( a1 ^( }% X15 {  / `' `: l" |* c/ [, b
16     mqd_t posixmq;  
  ?2 |$ ]7 {2 A! [. }. u4 y1 t17     int rc = 0;  : [* U3 G: w: @; d. [
18   
: U8 B6 V1 W( B9 j% `5 Y19     struct mq_attr mqattr;  
# T; O, N3 r! _8 Y7 F9 h20   4 O% n5 v6 }  n0 u$ C( o
21     // 创建默认属性的消息队列  4 q. ]' ]: p3 y" {$ H
22     mqattr.mq_maxmsg = 5; // 注意不能超过系统最大限制  % r" Y/ J7 `" X, [" G( x. `* `
23     mqattr.mq_msgsize = 8192;  ' Y+ F5 c1 `& [) ]
24     //posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);  4 x3 g* R; @" P# j0 r6 c& K% z" c
25     posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, &mqattr);  
# F. P0 p0 {& L. T7 V26 : g& Z9 ^6 ^3 ^
27     if(-1 == posixmq)  
, e4 V  q9 p4 y# W% t$ p28     {  1 v% P$ D) M4 O* o5 A: \
29         perror("创建MQ失败");  
' w# d6 X7 M1 Y& p/ i30         exit(1);  
, e3 _$ U1 U# J! [6 `; N4 h31     }  6 P) U. J. N. P3 ]6 K
32     ! b6 V, }( ?9 R% e! N: o9 s
33     mqattr.mq_flags = 0;  
( `& h  ?; ~4 `* h34     mq_setattr(posixmq, &mqattr, NULL);// mq_setattr()只关注mq_flags,adw  - N" P7 `3 U3 R  E; h. j5 I( M
35        5 f9 n, j: `0 X# s& T
36     // 获取消息队列的属性  
/ d" n  g/ g& p4 N' P8 q37     rc = mq_getattr(posixmq, &mqattr);  
$ N8 b: [( Y/ a4 A2 ?38     if(-1 == rc)  " l2 R* y! D! @$ E
39     {  
  n9 B# T5 \$ [* a0 S" Z/ h& {3 e7 r40         perror("获取消息队列属性失败");  
1 A. ~. ~+ C" `( p6 C# E41         exit(1);  " g/ t2 u  A) G! E  c& {: |8 E
42     }  
2 q$ a1 d( _/ x/ R43 ' b0 L; B9 j! W3 \5 G$ S) ?
44     printf("队列阻塞标志位:%ld\n", mqattr.mq_flags);  
# v& V, Y5 V6 s- c45     printf("队列允许最大消息数:%ld\n", mqattr.mq_maxmsg);  
$ F& a6 b# U6 ]4 B) H, a46     printf("队列消息最大字节数:%ld\n", mqattr.mq_msgsize);  
8 D. e9 m& {  @: w" ]/ \- V. e* K4 v$ R47     printf("队列当前消息条数:%ld\n", mqattr.mq_curmsgs);  
  \" v5 w( J* R48    * k- v: u+ z9 N5 t- R
49     rc = mq_close(posixmq);  * m4 B/ ^* R8 |6 T
50     if(0 != rc)  
6 h! {6 ^9 o3 X- z( Y0 l2 k51     {  
2 y  z3 @5 U! g% Q0 y, [& B/ v* G5 T52         perror("关闭失败");  9 \: ], M0 l* J7 E
53         exit(1);    \6 I2 y+ s# T. X0 D# a
54     }   
( c8 V# `9 P. i( @1 y; o55 8 B8 q9 H' ~( W
56     rc = mq_unlink(MQ_NAME);  " m3 B* Y& D) A" \: R1 @$ P/ f
57     if(0 != rc)  
- d+ ?8 ^4 {+ r% C6 F58     {  
4 I5 K9 y6 j+ G' O6 c59         perror("删除失败");  9 L: P# p7 k# G, F
60         exit(1);  " y2 b* T  j" z6 D4 y
61     }, O/ e( d# N) |( |
62         
* U1 C6 O9 t# i& b63     return 0;  $ D4 P& z4 A* s( l& z9 ?5 R. p: n
64 } / Q* J$ a+ a" G& u6 P

% `$ s6 `6 e' {! o! H! g0 d- ~$ ^; H" v% s$ x; E) a% u: f4 ~
编译运行:4 R( h2 a9 C. n2 \8 b

+ P' h3 n" a. a( x& q" Z1 root@linux:/mnt/hgfs/C_libary# gcc -o setattrmq setattrmq.c -lrt. L4 n/ m* ?* c2 S. @2 B. f, Y
2 root@linux:/mnt/hgfs/C_libary# ./setattrmq$ `1 s! T; [( A
3 队列阻塞标志位:0
3 V4 b2 i6 }+ P5 v! r6 x4 队列允许最大消息数:55 e! c% ~/ \' |7 b- U
5 队列消息最大字节数:81923 K% _: w4 V6 J7 R
6 队列当前消息条数:0
2 |0 E4 V# t. S' n5 A# ?: U, f/ @1 j. k* h! T) L, x# f4 W* u
! G# h, k' E" M; G- M
7 o  ~) u7 i0 V: N# Z+ d) I

" |" f" [  D" V
3 d1 ]1 B0 ^1 u# {& e, Q/ [: x* L
& k( q) a( s% Q% d9 I& `; J! i
8 ]! r  k0 V0 b% f$ |
  \5 r3 l5 }$ L- ?( _, D- t7 A  i7 I: c

3 y* o$ _& L. K/ }, a: ^3 N4 _& ]8 A% D# u% M4 ]/ W

作者: NNNei256    时间: 2021-4-26 17:55
IPC通信osix消息队列




欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/) Powered by Discuz! X3.2