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

IPC通信:Posix消息队列

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
% [7 i6 ]6 R3 M/ e& I& ~" D
 消息队列可以认为是一个链表。进程(线程)可以往里写消息,也可以从里面取出消息。一个进程可以往某个消息队列里写消息,然后终止,另一个进程随时可以从消息队列里取走这些消息。这里也说明了,消息队列具有随内核的持续性,也就是系统不重启,消息队列永久存在。: A, _) Y% e# m, c' y
$ i8 @7 T+ d, D* P7 D/ d  ^) b+ m* N
创建(并打开)、关闭、删除一个消息队列
' A: E& A7 w5 @, g3 K* f7 O, V
+ A! Y4 ~, c6 [8 G; c) a! ^" x- y 1 #include <stdio.h>  
1 Z+ ~5 a3 ?# J4 f8 B 2 #include <stdlib.h>
7 |. C7 V0 J2 ~2 L3 m 3 #include <mqueue.h>   //头文件% }+ d7 }9 G* y0 O/ g: T, r# ^$ B
4 #include <sys/types.h>  + S1 [/ r/ X. g4 o/ Q) P
5 #include <sys/stat.h>  
$ c; C& Z- E0 p 6 #include <unistd.h>  
1 t7 Y! |/ l7 V2 O1 w- r# `7 x 7 #include <fcntl.h>  5 e; J2 w) h' x- \6 v0 e) H  n
8 #include <errno.h>   
6 H# A% i( R' s9 U6 [& v; I 9
! V! B, V! F1 H( [: G0 ]& I10 #define MQ_NAME ("/tmp")  ( q4 a5 j5 m( b. _# l
11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag  , t& H- I! \, t( ]3 h
12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限  
! K' F% E' i; b) V: b13
2 S$ H% h: }+ m1 _! o) ?9 d+ D' j14 int main()  
1 y" {5 J  L5 L2 ^15 . a6 w2 X# u6 d9 Y; u0 {
16 {  
1 r$ X  a; W8 i$ a17     mqd_t posixmq;  
7 v7 H! e3 P4 q' |! W- S18     int rc = 0;  / g6 o  j' G) @$ v6 b/ V  W
19
, |9 W% ^, Q. j! L( {3 r8 `20     /*  , l/ x) {+ q! S  p1 K
21     函数说明:函数创建或打开一个消息队列  
. [! c  f( c$ _  b% [( t" H( K22     返回值:成功返回消息队列描述符,失败返回-1,错误原因存于errno中  ( c9 M; \) Y; k! P
23     */
1 F1 f% {: [0 M# b- Z24     posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);  
, Z& ^; f. m0 u3 W+ ^4 B9 j25 2 u0 b  Q0 m/ W+ D6 P( x
26     if(-1 == posixmq)  
! v9 I, u0 t( M5 d. F27     {  
6 M8 S6 z' \6 F0 D' o0 P5 C, d28         perror("创建MQ失败");  " }' I7 ~3 p& H! ^1 b* K8 R
29         exit(1);  
/ T0 L- ~2 @5 r0 b30     }  , x/ }2 ~, _3 U: l% z# }
31 + x" L" g* {+ S+ F1 h: ~- J1 v
32     /*  
/ s* O  r! v/ i2 k33     函数说明:关闭一个打开的消息队列,表示本进程不再对该消息队列读写  : Q* V3 ?- a, m4 u4 W5 I" N
34     返回值:成功返回0,失败返回-1,错误原因存于errno中  
: |" A4 S1 L- z35     */ 7 n* e9 @1 d$ {, ^' N, M  \8 |
36     rc = mq_close(posixmq);  
1 G/ S; H, I0 A, Q37     if(0 != rc)  
3 k! Y9 h! j6 Q. K38     {  
6 p4 w/ \! E2 O9 _! @39         perror("关闭失败");  
/ P7 [' |0 F1 C; ?40         exit(1);  
* k" V+ q) R2 k9 u( ?) {41     }    l! A8 x" `! h1 g
42 ' k( J+ i$ p$ o0 ~$ T
43     /*  
8 h* k0 i0 O* ?4 n9 @44     函数说明:删除一个消息队列,好比删除一个文件,其他进程再也无法访问  6 q% b( a% @4 l
45     返回值:成功返回0,失败返回-1,错误原因存于errno中  4 B: G0 l' P9 ]& ~2 S% ~7 d2 j
46     */* \) ~3 v5 f0 q6 ?
47     rc = mq_unlink(MQ_NAME);  3 P; B7 d8 z3 ?) c" I8 C
48     if(0 != rc)  1 a# s* d* V; N  Z; @+ [
49     {  
; A6 r7 K1 z3 k5 G& W+ I) O50         perror("删除失败");  0 e( y7 ]' V, Z2 X& N. R1 R
51         exit(1);  
' r8 Y4 W5 A3 ]$ i' s+ h52     }  9 G* i% r; o4 d3 D2 ~/ L, }
53 7 \( b: Y4 C6 q' q7 i9 [
54     return 0;  
( c; s* F. s" M55 } , e+ L2 d- N; q2 _
- S  [2 w+ _, c6 b) X. W

9 X% I0 \# K% `2 v; S0 R9 Y编译并执行:
4 @# ^6 A2 @- K% U) A
, i9 H) W. `) e: u7 w' g 1 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c
- m: D3 `" T7 M! N/ Y 2 /tmp/ccZ9cTxo.o: In function `main':5 n$ `+ _% m' {/ L
3 crtmq.c:(.text+0x31): undefined reference to `mq_open'7 k# o. q% W- J) V# _$ T
4 crtmq.c:(.text+0x60): undefined reference to `mq_close'$ J7 z) ?3 W8 q! d" T
5 crtmq.c:(.text+0x8f): undefined reference to `mq_unlink'* H7 s# }0 p, |$ b( z9 j( i
6 collect2: ld returned 1 exit status* S0 [3 ~% v. O8 Z1 f
7 因为mq_XXX()函数不是标准库函数,链接时需要指定;库-lrt;1 i+ A& Z1 a1 w
8 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c -lrt7 g3 a% f/ x: y2 p3 y! T
9
2 v( O8 x. f% e' {10 root@linux:/mnt/hgfs/C_libary# ./crtmq
5 v% Z) w- \) Z, B+ J11 最后程序并没有删除消息队列(消息队列有随内核持续性),如再次执行该程序则会给出错误信息: " u5 o/ Q* p' `9 a% X- B% j
12 root@linux:/mnt/hgfs/C_libary# ./crtmq " X2 G% ~. h- o, }* w; q
13 创建MQ失败: File  exit(0): q8 \$ C& |7 Z0 v8 v

6 M- B' v7 e3 [3 u/ L$ f! M$ X. D, c

& P" m) r3 X- D* P0 d  c编译这个程序需要注意几点:
7 m6 C4 V  I, J# Q5 ^3 Q6 q( W# F& ?' A- H& j* \4 {. k+ R
1、消息队列的名字最好使用“/”打头,并且只有一个“/”的名字。否则可能出现移植性问题;(还需保证在根目录有写权限,为了方便我在root权限下测试)
4 l4 B4 M5 Q+ U- X0 v9 p2、创建成功的消息队列不一定能看到,使用一些方法也可以看到,本文不做介绍;
0 _4 x' J% p& `8 L* U
* V+ ]9 \" a! n* P0 X3 o& e  消息队列的名字有如此规定,引用《UNIX网络编程 卷2》的相关描述: mq_open,sem_open,shm_open这三个函数的第一个参数是" G( @2 U$ K, b; P  R9 [3 B
一个IPC名字,它可能是某个文件系统中的一个真正存在的路径名,也可能不是。Posix.1是这样描述Posix IPC名字的。 / S$ d5 ~, u. y' h  l" [
1)它必须符合已有的路径名规则(最多由PATH_MAX个字节构成,包括结尾的空字节) 2 R$ Y/ G% C, |: k3 K& }* \
2)如果它以斜杠开头,那么对这些函数的不同调用将访问同一个队列,否则效果取决于实现(也就是效果没有标准化)
: T3 E& q; }9 I3)名字中的额外的斜杠符的解释由实现定义(同样是没有标准化) 因此,为便于移植起见,Posix IPC名字必须以一个斜杠打头,并且不能再包含任何其他斜杠符。
: i, J# N+ y7 P( w) @  a7 b1 x2 ^& O. Y( O7 n

: m7 e2 |9 j8 r! k: \" t" YIPC通信:Posix消息队列读,写/ ], Y$ }0 N- O8 b) o
2 Q4 H; T1 p" w) u
创建消息队列的程序:
8 m. J+ L1 X3 E( d' x0 u  E& D7 W6 K: Z6 U' Z4 Y% J
1 #include <stdio.h>  
$ @' f( M) ?1 B$ Z) _; ?" G 2 #include <stdlib.h> : g* R* V* ]; F* ]. `6 u
3 #include <mqueue.h>   //头文件. f+ d. B- n( b- n: Y4 {( ]4 v7 m
4 #include <sys/types.h>  + |) O" ]$ R3 k7 A. D- o
5 #include <sys/stat.h>  
; c* o4 O( c" C, U3 U# b8 W 6 #include <unistd.h>  . C9 V7 q) S" ~
7 #include <fcntl.h>  ) i+ R4 z9 o, I4 a; W6 Y, M  p
8 #include <errno.h>   
  m! D" \" e4 y2 N6 | 9 & T1 p3 w6 b; _1 h  i4 Z+ ~
10 #define MQ_NAME ("/tmp")  7 ?* N( X7 c( K2 F  ^
11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag  
* g$ j" ?$ _9 ?0 t' Z. n12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限  
. M- E$ m; H. l1 m13
' Y& l6 c! u+ R7 h14 int main()  
5 g, L1 H$ |+ P& z$ k; q15 5 g8 G# U5 e1 \# t  l% X
16 {  
7 ?9 g0 P  ?$ y) z7 f6 N17     mqd_t posixmq;  
: ~* d! M- Q) F6 Y' v18     int rc = 0;  
9 v0 h9 G! U7 |( S- c2 r0 w19
7 V* B, J) [4 h7 m4 W# }" p" A20     /*  
+ {$ w$ C/ `0 Q+ T' }* z21     函数说明:函数创建或打开一个消息队列  
' m) t0 f* G9 P+ P22     返回值:成功返回消息队列描述符,失败返回-1,错误原因存于errno中  1 j8 O/ N, |( X
23     */ 2 ]2 q) y+ Z3 \$ b9 Y% {
24     posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);  ' |0 \* S/ Y; A
25
! ^" J! l% h0 c( b* Y# v% `26     if(-1 == posixmq)  
7 S5 Z$ D0 x, p27     {  # g/ n7 D, f4 ^. j# _
28         perror("创建MQ失败");  
9 L( ?( W: E4 F. Q$ y% v29         exit(1);  
' [2 F. [3 W5 X' L2 `30     }  ' O* T+ B5 \: I8 _0 C
31
2 k. S, z) }) v* R+ m1 Y32     /*  
$ D3 P4 v3 M" k1 H3 y( L33     函数说明:关闭一个打开的消息队列,表示本进程不再对该消息队列读写  
9 [! f7 B) i! Y" {' C3 x. x8 V34     返回值:成功返回0,失败返回-1,错误原因存于errno中  
3 `( \# u: P: m- I35     */ ! d; p: a/ z$ m
36     rc = mq_close(posixmq);  
0 @1 z* j5 _4 U1 ~+ g, R37     if(0 != rc)  
7 p4 ~; m; x0 m; I( x4 l- l" ^38     {  
  l) d& y- ?2 O, t3 e39         perror("关闭失败");  
" u# N% @  E- N* A+ Q1 a40         exit(1);  
* H/ `4 `6 ~. Z0 j" F& K3 t% ]- z: p- b41     }  
* `7 t5 s- \8 z42 * Z' S  L% U+ U" j! ?6 `$ i
43 #if 0
. [+ Y* u8 E" M: M3 e44     /*  5 d  K/ p+ p$ t& w- ]; m
45     函数说明:删除一个消息队列,好比删除一个文件,其他进程再也无法访问  6 C! P2 T' J7 f6 o. K- k2 T
46     返回值:成功返回0,失败返回-1,错误原因存于errno中  
% K! E" v' B1 w2 D" n2 {( U  A47     */
" ~$ D( `" u6 d7 z4 J% j48     rc = mq_unlink(MQ_NAME);  & l) T& V( l9 b* Y. d
49     if(0 != rc)  ' i* B2 d% c3 D' X
50     {  2 K* x; N. l( z( e
51         perror("删除失败");  4 p1 `- }7 P8 [- k" Z( `' e
52         exit(1);  
" u6 v, f. y8 Y53     }  
! a$ N: x7 O1 E( {54
" E, |" O3 n, z! D1 T% T7 T# O) U55     return 0;
0 U* S7 C7 C, d% {7 c. I$ F56 #endif  ; |0 q8 [1 I  {
57 }
, x& [6 W4 j# _3 {% m, t. Y7 V5 D! |* q, P. X& a1 V+ y; w
5 y3 j) O' Y1 t3 K- Y' [% L
7 h5 e5 Y2 g" S
编译并执行:4 M! j( P/ g3 T) G$ ]
& T6 n( R; k' P9 W8 X
1 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c -lrt7 n& L( V; R9 s6 R- I
2 root@linux:/mnt/hgfs/C_libary# ./crtmq
: x. J& E) y6 P+ z( s+ W' ^" k3 程序并没有删除消息队列(消息队列有随内核持续性),如再次执行该程序则会给出错误信息: , W/ D5 g. b2 |: Z0 ~2 Y/ T
4 root@linux:/mnt/hgfs/C_libary# ./crtmq ' x* l) ]) V$ k" O- X
5 创建MQ失败: File  exit(0)  T/ E+ I9 F4 A

* W# o0 Z! W0 n
, ~: I+ D; `9 M$ G向消息队列写消息的程序:
7 O% v! a1 _, F, ~/ V+ P
2 i0 J% [5 n3 }- y% |+ 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 */
  • };4 S! v5 p3 d3 Y6 K& D
9 \& {5 l( L0 j& c8 \* f% N0 a$ K" \
- |  H/ Q; `7 j1 U2 T5 ?
0 }5 m* `& f( n3 \9 |3 Y

! d" n6 m! x7 ^2 R  V
4 Q  L7 g  l% c7 o2 U* x0 G 1 #include <stdio.h>  ' S# @' K1 K, _) V! I, i% g
2 #include <stdlib.h>  ) H% x7 C# X* G, x3 q' a. W
3 #include <mqueue.h>  
7 u2 m$ x& s3 k! O* b! f% H' k, U 4 #include <sys/types.h>  * q/ o6 R: v) I$ }
5 #include <sys/stat.h>    K5 L, H& q: q) D5 J. q# x
6 #include <unistd.h>  ; }% L% x7 a, c: c5 u1 U
7 #include <fcntl.h>  : `% F! b( {5 ]
8 #include <errno.h>  $ T+ x0 ]7 `# q+ D5 \( g
9   
' W) e. p0 k# D10 /*向消息队列发送消息,消息队列名及发送的信息通过参数传递*/ * p% c4 T9 p9 K2 t
11 int main(int argc, char *argv[])  
3 y2 Z6 R- ?# a/ d7 Q12 {  
6 ~8 w  T- i/ C$ O, U' n/ z5 O13     mqd_t mqd;  
4 Q8 _. d% r3 W0 a4 d14     char *ptr;  % d+ V$ c# ?9 V0 U2 `/ Q- c
15     size_t len;  , H. S, p0 T: m
16     unsigned int prio;  , Q' M, M  ~( L8 S
17     int rc;  
8 |+ _; M) D* o; o18
$ O0 r: @; r: @9 S0 F" r19     if(argc != 4)  
& r+ x! z  C: D) P) A20     {  
' Z$ e/ Z& s! L# Z+ }21         printf("Usage: sendmq <name> <bytes> <priority>\n");  
5 z' c- |$ J7 }# G. O, j22         exit(1);  2 Q" Z. D: s, y. R, Z2 m
23     }  
5 m3 ^% G* |4 U5 r* F24 , s. X" f  g% O( x: ~
25     len = atoi(argv[2]);  . Y, v# X# o9 L* I. p2 r% w
26     prio = atoi(argv[3]);    , Y$ g+ A+ [6 t1 ]* x! B! C- W
27
' E6 U' M2 c. U2 A" ^7 [/ V28     //只写模式找开消息队列  ! x6 a% J" g% M: t* Z
29     mqd = mq_open(argv[1], O_WRONLY);  
# ?8 v9 d* a3 p: \2 n30     if(-1 == mqd)  . e: Q2 h5 k6 N. T% S$ E! V
31     {  
2 E$ ]  S2 h) \. t7 a' P32         perror("打开消息队列失败");    N( p& j( Z1 ?% X9 w5 t' j
33         exit(1);  
0 W% G( P% P# P4 C5 W- n- z, l" l34     }  
, }- `) \  Z( A/ [. B8 W$ J4 f35
! H( I" F. C' v( r36     // 动态申请一块内存  
5 h! b& G5 V1 w. R37     ptr = (char *) calloc(len, sizeof(char));  
# H: H+ ^" P8 j; V1 B( i9 a38     if(NULL == ptr)  
; G. O7 @7 t; i& `# f! K& d39     {  ! {4 e' x  W* s% F& Q& E. Q4 x
40         perror("申请内存失败");  # F% d5 W8 u, T# k
41         mq_close(mqd);  ( J  Z8 Z5 g7 H% n* H; B/ u( C2 r4 \
42         exit(1);  ) V& N/ L" q; q* D1 I
43     }  
. L3 M) ]( r) f, Q4 Q) I7 W6 z44   
# L0 Z4 M& E8 o8 T8 A' g: r45     /*向消息队列写入消息,如消息队列满则阻塞,直到消息队列有空闲时再写入*/ ( w! E1 {1 `" \9 u
46     rc = mq_send(mqd, ptr, len, prio);  7 Z: c- X- \! T& u
47     if(rc < 0)  
- b' g& _( |: o- R48     {  ' q1 C/ Y1 d( L! m1 u) L0 N+ a
49         perror("写入消息队列失败");  
. C; H' A$ }7 Q. Z' J6 G8 l50         mq_close(mqd);  
; ^! n( _% R1 H& [4 L51         exit(1);  
2 Z: t* A1 L4 Z$ F4 x9 n52     }     
$ x' Z& B, K3 A5 W! |+ j. [53
" x0 v! ?/ ?+ x7 S54     // 释放内存  
) G) `4 g! N" g; v9 n& [( l55     free(ptr);  1 a* U1 k9 F# L6 I
56     return 0;  9 l& F( K: v7 ~4 j% a
57 }
$ a! I6 Y* d3 j% C. x
) U5 Z& ]( e3 Y/ k0 e8 o7 E
3 \) ^, X8 w6 a. @编译并执行:
4 V& J* v6 p3 C- O# [. J
, e+ T  T9 O! E; @) O' ^3 @. X1 root@linux:/mnt/hgfs/C_libary# gcc -o sendmq sendmq.c -lrt
5 D$ ?8 k: |: O; |, `2 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 15
; n1 |7 {/ c/ U- S3 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 166 B# y! G3 z3 c4 ]
4 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 179 @1 Q- m, X5 z+ S5 N
5 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 18
' p! S* t; Y6 g% j1 d) _4 l- K2 R6 B2 h! F( C, A+ T
  上面先后向消息队列“/tmp”写入了四条消息,因为先前创建的消息队列只允许存放3条消息,本次第四次写入时程序会阻塞。直到有另外进程从消息队列取走消息后本次写入才成功返回。
6 v" }* Z" r/ ^% ]0 @0 k
/ m1 o- g$ |* R: b% y6 [  U4 t& S' _9 \# |' \% J
5 k! i4 w* L0 G
读消息队列:+ D! b) l9 H8 T# ?8 @7 `# @2 m

- u* O4 L; F! P" f* [# O" U) @#include <stdio.h>  
1 ?. v: j! o( T#include <stdlib.h>  
/ B& a# j: M0 W$ n- T#include <mqueue.h>  $ y3 ^* H( v/ _; h+ Y4 S% w
#include <sys/types.h>  
' S; N3 X! v. p! `( R6 S: Q6 D1 |#include <sys/stat.h>  . b, k) ~, ]4 |, |( ?2 h$ O
#include <unistd.h>  
$ I3 V, A) u0 B) q5 D! y* K3 f  J#include <fcntl.h>  " S# H, k1 F4 l% ~2 m0 |
#include <errno.h>  ' i8 D+ c6 G4 ]; E, t/ n, m- a' w+ S

& q/ v& T3 Q4 ~2 {" ^* ]/*读取某消息队列,消息队列名通过参数传递*/ : N: o6 ^# M& o# N3 E: |
int main(int argc, char *argv[])  
( G3 ~. V2 \& Q+ W{  1 o5 s+ J% F, L1 S& ~) W$ S8 L
    mqd_t mqd;  
0 Y1 d& X9 u- e7 C1 N    struct mq_attr attr;  
  ^' ^' |4 R2 ~2 H    char *ptr;  7 a, i  z1 {8 e7 }4 ^9 r* n
    unsigned int prio;  # m0 t& j+ F$ r0 R0 o0 o- S
    size_t n;  4 Z5 j) a' o* o6 [4 P
    int rc;  8 l) Y3 f8 m/ e# J7 E
3 X9 Y5 M( F- h0 o" a
    if(argc != 2)  2 N! g8 C+ J3 A( S
    {  
1 u; \! R' ^  [* f        printf("Usage: readmq <name>\n");  
+ K# p3 F' L% J/ M6 h        exit(1);  * Z1 ^% |! z. _: R! {0 `
    }  5 t' q- d! U4 B8 W* h; Z
) ]- m3 c$ V0 b. u+ m
    /*只读模式打开消息队列*/ 2 \9 }# o4 Q/ \7 y" w6 k: |& I& ]% R
    mqd = mq_open(argv[1], O_RDONLY);  
, B' k6 l/ b0 V( @! }    if(mqd < 0)  0 c" ^# j5 y3 Y: R% t! o
    {  
9 B+ V: A- I2 s+ C5 g6 ?        perror("打开消息队列失败");  
3 @2 C9 K( \, r2 R/ `        exit(1);  
6 ~4 c$ ?2 w" y$ A) U( \5 P    }     + {! @; r) p! ^& A

8 f4 l+ \! G4 O! p" D    // 取得消息队列属性,根据mq_msgsize动态申请内存  
/ c7 g9 D; x  ^    rc = mq_getattr(mqd, &attr);  " a2 T( P8 e7 u7 E( N; w
    if(rc < 0)  $ X- r6 D2 f3 C: b- P9 k0 b( A% O
    {  
4 _- k7 t( e  g$ O. \        perror("取得消息队列属性失败");  1 q3 N% X, g2 V* e
        exit(1);  4 t6 C8 O4 ?$ m; s
    }  
' n: C; f8 _3 D. H( A9 W4 F& J0 ~: w9 H* v7 Y
    /*动态申请保证能存放单条消息的内存*/ . @3 j1 r, i# o5 m) W, o
    ptr = calloc(attr.mq_msgsize, sizeof(char));  
3 X! m. W- }- i$ I; _. n- a. e    if(NULL == ptr)  3 y! N$ [% _/ E# w; n" b
    {  8 Y' f. ?" R& a& K& X. ?
        printf("动态申请内存失败\n");  9 B* u7 y+ }& t0 s
        mq_close(mqd);  
' ?/ m! l4 S' F' q/ u        exit(1);  
! p' p. z, f, V  Q/ O" t# q4 i    }     
0 e% f3 M$ ^4 _' c7 }5 t; L: J$ x( ?
# r$ y; e* v0 M+ D. E& N' v    /*接收一条消息*/ 8 T2 \. u" I7 T7 X6 g
    n = mq_receive(mqd, ptr, attr.mq_msgsize, &prio);  $ t, ?( d+ S2 ^
    if(n < 0)  
4 Q4 O' P9 V  a2 k1 W& \    {  
6 l3 J( i/ b1 t/ {9 h        perror("读取失败");  8 f4 X: }" \- f. ]' E, D  [, j
        mq_close(mqd);  ; @7 @/ D9 [8 E4 u& x& n
        free(ptr);    X/ s! q8 U9 ?
        exit(1);  
, l9 D  \( B0 {6 |( Y    }  
4 N1 o+ M5 F' ^    $ W3 l$ B* z; J% S: Y
    printf("读取 %ld 字节\n  优先级为 %u\n", (long)n, prio);     
& E" g. @1 f' e' W5 A& G( o    return 0;  
$ Z7 Y0 d/ k) Q$ w6 e}
# y2 A4 b( \3 v; i* m, D
0 o1 Y+ c# d* W# l: Y% @5 A7 W) s6 u

) s- }/ L( |" X/ K编译并执行:
1 e, h% ~5 |3 F& K0 h# i+ \+ X7 {0 X% n2 o
1 root@linux:/mnt/hgfs/C_libary# vi readmq.c
2 x  s, T' A. p# H; |" h, q  A* _9 N 2 root@linux:/mnt/hgfs/C_libary# vi readmq.c, E, ^0 k! f$ A# r9 u9 R
3 root@linux:/mnt/hgfs/C_libary# gcc -o readmq readmq.c -lrt
; I! `8 [6 ?; E9 i' F 4 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp; Q; H8 {# J" Y1 w# ^3 R
5 读取 30 字节
9 ^7 l. I9 b8 S: T 6   优先级为 18  T  m4 r' P, m; ?
7 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp4 ]; W& C7 z; m/ k5 T7 H
8 读取 30 字节
* j# \5 X$ ?6 q 9   优先级为 17
' e, m+ V; j8 A" n/ H5 z10 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp, ^' q( |# n$ _9 `
11 读取 30 字节
# |& D& r: u9 X/ p; K! {. z# {9 b- z12   优先级为 16
3 w! ]/ N5 P& _# s) M& w13 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
7 @* W3 |  `! q8 k14 读取 30 字节
- C# C5 L" [2 A15     优先级为 157 {, M0 f2 {, [3 \, o4 f
16 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp+ [& Q: H4 D$ ]9 w! P& `1 _! i
( i3 }" a1 n& C$ {( D, s& R

* s% \4 b; s# {4 R' a! R
9 ?$ ]5 Z3 w6 G3 k  程序执行五次,第一次执行完,先前阻塞在写处的程序成功返回。第五次执行,因为消息队列已经为空,程序阻塞。直到另外的进程向消息队列写入一条消息。另外,还可以看出Posix消息队列每次读出的都是消息队列中优先级最高的消息。
9 j9 ~0 ]  Y" k9 u
: f/ V$ R8 G8 S$ A$ _
5 c4 r" \: z- B& y- W3 @- A2 C7 [8 r; y1 }" U8 z) n
IPC通信:Posix消息队列的属性设置1 z0 `* e8 t& i% \* r

3 Y( H: u/ ~$ 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
    3 d6 S0 ?% V/ N, U4 X; k
: M( b8 K8 [; n  D  U3 r, S
6 A: y' E3 i% T2 h
程序获取和设置消息队列的默认属性:* v6 W4 u/ A; B; F, o% h$ _2 k

! {2 o: {1 K2 t7 P 1 #include <stdio.h>  
1 _0 }/ ^6 T+ q3 l$ ?+ K8 c 2 #include <stdlib.h>  / ?+ B) D/ X2 {6 B  B
3 #include <mqueue.h>    r/ x* h# |: y% W8 ~  ^
4 #include <sys/types.h>  
: u; D! C8 h% V/ Y6 E 5 #include <sys/stat.h>  1 ^! r  v4 R8 t" V0 Q8 w
6 #include <unistd.h>  
0 H- i. K2 _/ w3 U, w& a+ ? 7 #include <fcntl.h>  # U* X$ h$ g- U) o( ~" i& S# H0 @
8 #include <errno.h>  ) t! a! J5 v7 m; b  |4 B$ h
9   
& e- S, c0 j* `7 K; U& O3 n10 #define MQ_NAME ("/tmp")  7 D. \$ _  D$ h8 s9 G
11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag  9 D. S+ i3 r; Y- ~+ V/ |/ |
12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限  : q8 D7 G- l- e1 r" [1 C: y
13    3 E1 L/ }8 T. s+ w# \" I
14 int main()  
/ l; O6 G! N& G/ \15 {  7 _) v" Q% ?* i  Z" J
16     mqd_t posixmq;  
  A9 I' ]  L7 [, B6 b  @, z17     int rc = 0;  
' N6 V5 l5 j3 j! Q% u' r18    & B3 @* u4 X# L! Y. s
19     struct mq_attr mqattr;  
% `0 s! o, b$ T- _; x20    + p8 x0 [, P5 E0 t; k& t
21     // 创建默认属性的消息队列  
! ?. }; M4 E1 u. P22     posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);  
- X: \! S5 \9 q) C/ z1 t23     if(-1 == posixmq)  ; q- R; G( f, R( M2 K- x" M
24     {  + o1 i4 f7 Q: O
25         perror("创建MQ失败");  - o1 P- @( P9 u% S
26         exit(1);  8 K* u) `) h; I/ S, |4 [$ @& M
27     }  
! X2 N6 |% y3 x. X, b28        . R4 X& S/ z* Y, t! C
29     // 获取消息队列的默认属性  
9 P& Z- V) C6 l* H' G30     rc = mq_getattr(posixmq, &mqattr);  . q* `6 Q+ a" s+ k( i
31     if(-1 == rc)  % q2 d: O: b+ \1 I- ?# f8 ]6 a: C/ I
32     {  & a. w$ S7 A# l+ }
33         perror("获取消息队列属性失败");  - R/ t8 H, R, }1 ~( p+ K8 G
34         exit(1);  
6 D& r6 ~9 ]( f4 H35     }  
; n, z! C6 \, F& K4 Z& ^( b36
& L) L: P& X4 z2 e2 v. T37     printf("队列阻塞标志位:%ld\n", mqattr.mq_flags);  
/ K+ e1 K$ h7 s: i+ [# \38     printf("队列允许最大消息数:%ld\n", mqattr.mq_maxmsg);  - r$ g: b' H/ ^; H. b
39     printf("队列消息最大字节数:%ld\n", mqattr.mq_msgsize);  
: l  p0 P. L0 R1 e; m( }0 }40     printf("队列当前消息条数:%ld\n", mqattr.mq_curmsgs);  4 [- {' @/ |- @1 }4 |
41   
/ t! `3 o. J. h* H: z' y1 H42     rc = mq_close(posixmq);  6 I: Z0 U/ ~# o* b( j6 w& O
43     if(0 != rc)  / Z& R1 o" d0 o% Q. ]$ _
44     {  . |0 N) J. P" q  h
45         perror("关闭失败");  7 x" L: F. O) a8 ~
46         exit(1);  3 l7 Y' W+ P  A0 M8 Y# z
47     }  2 L4 U4 T4 u& K6 O5 N
48    ( K& ?7 ?+ c2 _* M# w0 K# N' ~
49     rc = mq_unlink(MQ_NAME);  
9 A! e3 p8 L8 D% o* {# v50     if(0 != rc)  
- F5 ^/ D( O. l+ T- F51     {  ! p+ s% D: R, u9 d9 e% G
52         perror("删除失败");  
. J: x2 J+ @7 z" B4 H53         exit(1);  ' b- P: M' U& S
54     }     
% Z* Z0 z  [8 h; x55     return 0;  
, r9 a) R; l8 z! h5 O5 c56 } 8 [) e) ^' T$ }! t1 b0 Z, O) k

2 r. i  ?9 f) J/ r" @2 R8 F# y) e: V$ V" r
编译并执行:$ F: h0 Y( ]2 T1 W+ l
, ?( M3 F1 k) G$ K& b2 [
1 root@linux:/mnt/hgfs/C_libary# gcc -o attrmq attrmq.c -lrt
. Z- \1 ^  ~: q$ J* U/ {2 root@linux:/mnt/hgfs/C_libary# ./attrmq. a) m, s* n6 o+ e, r
3 队列阻塞标志位:0# @- t. d% b7 ^3 C; {* ^1 M
4 队列允许最大消息数:10
7 {. V- q( \+ O* y5 队列消息最大字节数:8192
, p  j! [' z: n# f% `& ?- v1 V6 队列当前消息条数:0, u8 a4 Z" Y: i
7 root@linux:/mnt/hgfs/C_libary# - p- a! Q8 M5 i, L0 V  w: M) f9 g. C
/ L1 ]" a% s6 p* l

' I6 Z* L; y# n设置消息队列的属性:
- T/ u( m% H/ z" }' s# w: w
) N* G6 p5 `" f7 E. y: m 1 #include <stdio.h>  
$ v4 G' A5 S! v' ~7 T& F. S3 A7 i 2 #include <stdlib.h>  ( D  S- n& {5 D/ ]$ }0 g
3 #include <mqueue.h>  
, w- E8 }) [8 z# j! X) @; e. o 4 #include <sys/types.h>  
& [! {$ s5 i8 W/ S5 n, G/ q4 y5 s 5 #include <sys/stat.h>  
; n6 y- z: K7 E% r2 i8 e8 t 6 #include <unistd.h>  
0 ^# z) h- F6 C 7 #include <fcntl.h>  
1 T0 \! w& J2 k0 p( K, [ 8 #include <errno.h>  0 w# |1 O( |5 l" n- {
9   
' B! j; d- p) C. B10 #define MQ_NAME ("/tmp")  
" l' S1 j. h8 A+ Y  S) I) |' ]. G11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag  5 t3 M6 |6 G; a* _; v- ]( n
12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限  
  z3 K( i5 m- L' {13    & G9 H( D) Z) M5 N4 g# ^% c
14 int main()  # ^* ?( }6 f' b
15 {  2 `7 e& N' n, ?0 l% F
16     mqd_t posixmq;  * W2 F3 j( |3 d2 j
17     int rc = 0;  & ]) ^' [( h" o* ~
18   
) M& y! ]# h: ^; c19     struct mq_attr mqattr;  1 O% k6 o( m) T
20   2 M( B& }5 K% }
21     // 创建默认属性的消息队列  2 r' J. K8 R5 u9 a. Q6 i5 ]
22     mqattr.mq_maxmsg = 5; // 注意不能超过系统最大限制  # {& q3 X9 {' j; q! I' X
23     mqattr.mq_msgsize = 8192;  
# f. ~+ o- A' X1 J( |24     //posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);  , ], ?6 J5 M) B4 G2 S
25     posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, &mqattr);  2 w0 g# B6 r. V. [2 U0 [
26 * [1 j2 F  x5 T* O$ Z# X+ z
27     if(-1 == posixmq)  
7 T6 B5 g! c0 Z: [5 N4 R28     {  
; f1 e3 t& \6 a; x% \+ i. s; Y29         perror("创建MQ失败");  5 r( e* q4 K& V- H8 \0 Q: v
30         exit(1);    P9 A) B  t( z0 f
31     }  6 Q5 Y: k' R9 m/ g
32     
# _1 ^' a, k: V33     mqattr.mq_flags = 0;  : B$ {( z  d( }8 W& Z9 Y
34     mq_setattr(posixmq, &mqattr, NULL);// mq_setattr()只关注mq_flags,adw  $ p1 c  Y# l% i% C- |( G* s
35        
) j5 x" Z1 a& i8 z) F. y36     // 获取消息队列的属性  " N% W8 Y2 z0 ]
37     rc = mq_getattr(posixmq, &mqattr);  
. i& a+ O1 z" I2 O% G38     if(-1 == rc)  , A3 S3 f% I8 w8 X) D% p3 v
39     {  8 \% d, F! n( B8 F3 {
40         perror("获取消息队列属性失败");  4 u0 Z! }( s" `# P1 K
41         exit(1);  2 g4 h* u/ N' e6 `9 n4 I- w- s3 f
42     }  
- M' E, d6 v1 D( n3 |9 x& f- q$ U43
+ `* Q) I; U9 ?2 Q* A' V44     printf("队列阻塞标志位:%ld\n", mqattr.mq_flags);  ; k3 T8 R! A- N: v
45     printf("队列允许最大消息数:%ld\n", mqattr.mq_maxmsg);  
7 ^5 Z, h; H+ R3 Z& I/ Y: J/ \46     printf("队列消息最大字节数:%ld\n", mqattr.mq_msgsize);  ; \; F8 [' q0 g5 J# m5 v- G
47     printf("队列当前消息条数:%ld\n", mqattr.mq_curmsgs);  
6 `4 o; D+ j* A# p+ d48   
$ K0 y. l) ~9 l3 j2 k0 Y49     rc = mq_close(posixmq);  & |4 s+ L. t+ J2 i% j2 Y$ {) J9 Q
50     if(0 != rc)  
' Q6 _6 ]5 h5 i* r- X% S+ ]6 r: d5 m8 Q51     {  $ a' G$ x1 Y+ f* u+ G
52         perror("关闭失败");  ! a( E: p" }( X7 k
53         exit(1);  $ L1 Q# Y) p0 E9 Z4 E, L
54     }    % z# |: ?4 P3 s$ |
55 ( }( r/ O/ j/ v4 ~* y1 f
56     rc = mq_unlink(MQ_NAME);  . T3 r: C* [. G7 j- n
57     if(0 != rc)  
0 s# q! {3 g6 F' A4 B; b. H58     {  0 m; R+ @5 b9 k; c& |; @# s- J
59         perror("删除失败");  
  T9 D0 K) d) D6 G5 X60         exit(1);  4 f/ t8 c. k7 G8 W$ c' V
61     }; K- C$ K0 R! i: b" A) `
62          & q: D3 N; ^3 q% H7 s- j
63     return 0;  . D% n6 C4 d8 N
64 }
9 M* `$ z% ^! {  c- y2 B: u' S2 q) h# G; V, j- ~; p& J' F
4 q# }' F8 U8 b3 d
编译运行:
5 B  N; q) a5 f  h- F, w
+ k, Q0 v. {, t1 B+ L1 |8 }1 root@linux:/mnt/hgfs/C_libary# gcc -o setattrmq setattrmq.c -lrt$ K" t% j$ p8 g5 w9 A/ E2 I
2 root@linux:/mnt/hgfs/C_libary# ./setattrmq' S7 Z% v7 y& Z5 h7 e
3 队列阻塞标志位:0
; i4 B" `; {% ?0 h/ l4 队列允许最大消息数:5
2 z8 k. `4 I7 j& ~. u5 队列消息最大字节数:8192  g1 ~4 ?: G) ^
6 队列当前消息条数:0
8 N  F- A0 r9 a  j
% F( z6 A  N  i# [9 V$ M6 ~+ H' v. r* f

9 j9 w% ~% X" q. i2 A6 E  R  s% u2 b0 @+ l& i

, k8 V. d) `# T+ b+ G1 W* y$ }4 J9 u* G

# I4 `/ a7 O: h( P# U- q$ @: E. H( x( b
4 q$ M) [, _1 c+ Z; F

1 |8 |: O  ]9 v) m% e' B( Y
5 t, R3 y9 K5 V0 b+ r) q. J* [3 k$ v

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

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

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

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

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