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

IPC通信:Posix消息队列

[复制链接]

该用户从未签到

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

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

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-11-24 10:45 , Processed in 0.187500 second(s), 24 queries , Gzip On.

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

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

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