找回密码
 注册
关于网站域名变更的通知
查看: 469|回复: 1
打印 上一主题 下一主题

IPC通信:Posix消息队列

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2021-4-26 17:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

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

该用户从未签到

2#
发表于 2021-4-26 17:55 | 只看该作者
IPC通信osix消息队列
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-11-24 12:12 , Processed in 0.156250 second(s), 23 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表