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

IPC通信:Posix消息队列

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x

8 G+ V& J2 M5 d- g$ d# v9 p1 Q2 M5 \1 Z 消息队列可以认为是一个链表。进程(线程)可以往里写消息,也可以从里面取出消息。一个进程可以往某个消息队列里写消息,然后终止,另一个进程随时可以从消息队列里取走这些消息。这里也说明了,消息队列具有随内核的持续性,也就是系统不重启,消息队列永久存在。6 Q8 M( J4 y  M3 {
! I8 v! g  }! }6 L- A3 q3 ?& l, a
创建(并打开)、关闭、删除一个消息队列" [; c1 _# F  ?& i0 V& j. u, N
8 A" T/ f) U0 M, W7 T
1 #include <stdio.h>  9 Y* E% z& d% c5 q$ s1 {
2 #include <stdlib.h> . D3 u* l. y" |2 k% i- m
3 #include <mqueue.h>   //头文件( Z, C' e8 F9 z2 Z
4 #include <sys/types.h>  
1 z4 i% ]  s' N$ e 5 #include <sys/stat.h>  , E/ f  \% q  D. K1 ?3 \" @8 U
6 #include <unistd.h>  
: @: ~" O( y, j# U" b9 F* z 7 #include <fcntl.h>  " j9 n8 M0 U  c8 l) Y9 Z
8 #include <errno.h>   
$ m: t! E6 \" Z6 z 9 # H3 }2 o9 a1 p/ ~
10 #define MQ_NAME ("/tmp")  
7 }( }! G" N5 Q0 y2 b' M+ L" s11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag  
% E( i" I& o+ N0 O% E; c12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限  2 Q5 q+ \3 t" e8 e' ^: ]$ j
13 & ~0 ^8 j' c% {" J$ u' M/ {) f
14 int main()  # J8 S1 p8 U4 t; o5 k
15
  i# h. \) g7 t, _# p( O16 {  
. [; v1 E, q) n* ^17     mqd_t posixmq;  # O: O/ c, b! }% {
18     int rc = 0;  
: n: ~! q0 E1 H- \# R, m. K/ ^7 I19 7 L0 u7 u& s6 l% a- m
20     /*  
3 A% w, |0 Y* B# a; `21     函数说明:函数创建或打开一个消息队列  
% m1 l! L+ s0 j22     返回值:成功返回消息队列描述符,失败返回-1,错误原因存于errno中  1 Q8 L: e4 x! ^0 j+ P6 p
23     */
& X0 H; r8 G! \24     posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);  ; H* f5 c: M; s/ E8 a$ V
25 " o7 h: u6 C7 o( e
26     if(-1 == posixmq)  + s4 O4 L) l5 A9 W& J. o( ?
27     {  ! @$ k- L# Y- @5 q0 |7 T
28         perror("创建MQ失败");  
% G6 m: h% d1 \. w; U3 C6 A0 z29         exit(1);  " y2 U" I3 [& w1 B3 K$ B1 x
30     }  " I5 X6 d3 [2 n8 C
31 8 \, i* V/ B  l; s. i3 e
32     /*    p; V% L- [0 \/ R$ n5 L
33     函数说明:关闭一个打开的消息队列,表示本进程不再对该消息队列读写  6 G. c; E+ R5 A$ W* E' s
34     返回值:成功返回0,失败返回-1,错误原因存于errno中  
1 H- c* x: D' @3 y4 d9 x35     */
- z6 @/ `& |7 m; O; G5 |7 M+ {* A36     rc = mq_close(posixmq);  2 W& e+ n" |, a1 J; B* H
37     if(0 != rc)  
. G, m- M9 k# P38     {  $ Q+ V2 ]2 N0 D1 X* x/ E
39         perror("关闭失败");  ! j/ T$ c* L9 h6 N/ H
40         exit(1);  
+ w* K! H/ ?* s% Y8 L# L' j41     }  ) F( }# h7 a! {2 E( A
42 ' H: N; I6 r2 z! E6 a1 U
43     /*  
/ x$ _1 s% b+ w! [44     函数说明:删除一个消息队列,好比删除一个文件,其他进程再也无法访问  
. s4 H2 m3 d0 _( U; o45     返回值:成功返回0,失败返回-1,错误原因存于errno中  
0 s) u" X7 P" ?* A3 b46     */$ i6 g/ d, M4 e
47     rc = mq_unlink(MQ_NAME);  - ^* r) ~1 d) A9 {& w
48     if(0 != rc)  
1 X! I1 V. z% o, z4 c49     {  ) J3 S7 `- [7 |/ U' m
50         perror("删除失败");  + q! n% h$ p5 y% R3 i/ W0 j
51         exit(1);  0 x( o7 ?$ ~4 @# H0 {
52     }  
+ n! h) I5 D0 j* y& p7 I4 U: `# e53 & _3 ~, w8 U. [1 U. S* i
54     return 0;  , B0 c- s) S' M6 N
55 } 4 t% u. {: n9 m8 q) u

# L" `7 D9 B/ l6 X! H8 Z
9 M+ R' o9 z, l1 v9 }编译并执行:; z# ~3 J: ^2 v  ^0 o

. u5 l  i( G0 d 1 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c
- a5 A. D0 l) \6 t7 ?1 {# [ 2 /tmp/ccZ9cTxo.o: In function `main':& d! D, q8 f' d  @8 E
3 crtmq.c:(.text+0x31): undefined reference to `mq_open'
2 Y" B  Y6 l, ^, L# p5 u0 x$ I. h 4 crtmq.c:(.text+0x60): undefined reference to `mq_close'
2 e) E, @! S6 O* S2 t& J 5 crtmq.c:(.text+0x8f): undefined reference to `mq_unlink'
3 L  z6 ^/ q, Z0 { 6 collect2: ld returned 1 exit status! m  a& H& E& M1 c6 e
7 因为mq_XXX()函数不是标准库函数,链接时需要指定;库-lrt;8 `5 M( l- r" G1 c3 _
8 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c -lrt; `; ]/ p1 z* L' Z
9 # M, R* v- u  J3 \* F) D
10 root@linux:/mnt/hgfs/C_libary# ./crtmq8 f7 c3 D/ M7 s
11 最后程序并没有删除消息队列(消息队列有随内核持续性),如再次执行该程序则会给出错误信息: ; [/ C7 M, A. Y# O( l
12 root@linux:/mnt/hgfs/C_libary# ./crtmq
, h) O% o' U, F+ F/ _; {13 创建MQ失败: File  exit(0)" q3 a- C' G1 c7 G$ f7 W
4 H( c: t/ T1 ?# Q* i8 r$ G: {0 l
1 k  W" W$ d1 Z

/ R  B$ t+ u* |. f编译这个程序需要注意几点:2 i, s$ g9 J; e; x$ d
6 w1 \5 t7 W* D/ k
1、消息队列的名字最好使用“/”打头,并且只有一个“/”的名字。否则可能出现移植性问题;(还需保证在根目录有写权限,为了方便我在root权限下测试)
9 Z+ Q# k7 X8 q4 l- F6 S7 y2、创建成功的消息队列不一定能看到,使用一些方法也可以看到,本文不做介绍;! ~; c- S* u3 `% o) y

7 `) H" w5 w& G+ i; v  消息队列的名字有如此规定,引用《UNIX网络编程 卷2》的相关描述: mq_open,sem_open,shm_open这三个函数的第一个参数是- P4 v- J9 U( m) M9 f
一个IPC名字,它可能是某个文件系统中的一个真正存在的路径名,也可能不是。Posix.1是这样描述Posix IPC名字的。
& c4 _- B: q) X8 U; x1)它必须符合已有的路径名规则(最多由PATH_MAX个字节构成,包括结尾的空字节)
2 f" k; v/ \: B* b  }# V0 H2)如果它以斜杠开头,那么对这些函数的不同调用将访问同一个队列,否则效果取决于实现(也就是效果没有标准化)
" C, p* c$ t6 W. f8 ]- t3)名字中的额外的斜杠符的解释由实现定义(同样是没有标准化) 因此,为便于移植起见,Posix IPC名字必须以一个斜杠打头,并且不能再包含任何其他斜杠符。
  c9 o9 S2 c7 @
8 a; _. ?# Y) L9 {  d: B5 Z# l1 l" Y0 S4 U7 |
IPC通信:Posix消息队列读,写# w/ \% P( h9 G! v
- i# \* Y  b; O
创建消息队列的程序:
, W  R8 y' `6 ?  s8 ~# J, O7 N; S9 r" J, I) b: i% }4 b
1 #include <stdio.h>  
  {& y0 {& i6 X: g6 H% y 2 #include <stdlib.h>
8 D* x* u- E# U6 v1 f2 {/ \2 ` 3 #include <mqueue.h>   //头文件8 l5 C, w3 |- l. \# @
4 #include <sys/types.h>  
4 `- a. z1 t' a0 z 5 #include <sys/stat.h>  ) G: R2 @0 f' G8 b
6 #include <unistd.h>  9 i( t" }6 h, G( o" ]. u
7 #include <fcntl.h>  ! W7 z. L- m% H  w4 n4 {2 @- r
8 #include <errno.h>   
1 u2 ^2 |. a+ L4 \' ^  y 9
& I; c9 r6 r. f6 \. S9 g9 z10 #define MQ_NAME ("/tmp")  ' Q' M5 c0 ^6 T8 k/ L
11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag  
. _" q, Y  S/ M1 H+ e3 k12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限  $ \1 m! s, t& \- M4 r+ ~
13
! ~( f3 Q' N( c! _2 X* \2 J0 O/ |14 int main()  & R6 \3 ^1 w( Y9 D$ ?1 Z1 G6 m  H  a
15 7 t: _8 Y7 m$ N2 e: y
16 {  
1 \7 c) c9 V, |- I4 \* o. a$ ?17     mqd_t posixmq;  
4 ]4 P' ~8 e0 j# _* M18     int rc = 0;  
! K' C$ I/ U# X/ Q2 g1 Q19 $ S9 y( z+ h5 h2 h+ [& Y* F
20     /*  " f6 S/ f5 ~* y0 l
21     函数说明:函数创建或打开一个消息队列  5 }; a, ?  U, _0 q+ U  Z1 v, a
22     返回值:成功返回消息队列描述符,失败返回-1,错误原因存于errno中  
9 [+ u$ K- _* K" K23     */
! G. v6 n6 h9 f* @% A, _# d$ X& O24     posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);  
! |5 n8 q- F8 k+ s! ^6 S25 0 }, K; a$ K7 q/ L
26     if(-1 == posixmq)  
) _5 f1 Q) g! ~3 K3 {& c- `27     {  
, L) p, g; w$ Z. m8 k0 b, k28         perror("创建MQ失败");  
$ h5 o( U+ {4 M# Y" J29         exit(1);  
9 C5 J6 W3 p3 Q8 R6 i' Y0 @30     }  
6 v$ \( n5 o& q& t! p31 . Q" i) u% T; a, K0 l. H7 o  \" x
32     /*  
/ }9 r! ?6 J% t% s0 k33     函数说明:关闭一个打开的消息队列,表示本进程不再对该消息队列读写  % J& ?+ {' o9 V: X  G  U
34     返回值:成功返回0,失败返回-1,错误原因存于errno中  . ~" s0 x( I. L6 {2 h  F: u
35     */
$ \: R. R' }3 _7 R- F36     rc = mq_close(posixmq);  % v+ g$ ^9 K" X5 N4 c4 x
37     if(0 != rc)  : k. F7 k8 k, z: B
38     {  $ q0 A4 a6 {9 T! ?7 w0 ^& Q% Q. }
39         perror("关闭失败");  . K" r3 @* h0 A+ g! n, t; c
40         exit(1);  
" J+ ^! T! q' q! {41     }  9 n& [+ P. `6 ]- I
42
: f$ O4 j  @# C5 G3 ^3 Z2 O7 r43 #if 0: ^8 k3 m$ a) Z- ~. c  r: H9 y
44     /*  
* e' M5 S0 Z1 ~4 p5 s6 |45     函数说明:删除一个消息队列,好比删除一个文件,其他进程再也无法访问  ) p' w( q* B; _% s  N  {
46     返回值:成功返回0,失败返回-1,错误原因存于errno中  3 w% [. S9 n" `0 T4 V5 O
47     */& O, [7 H9 ?, A8 r$ z
48     rc = mq_unlink(MQ_NAME);  
8 r& i1 j- k9 l3 O- m9 }0 u49     if(0 != rc)  
4 Z+ @  @+ ~( V4 _  B4 }50     {  
: \" ?& G1 a" d+ H! ^51         perror("删除失败");  ! u; f; Y3 }8 K& I, e& v2 }, F; j
52         exit(1);  
& n, t1 b4 Q; c/ }4 ?9 r53     }  6 ?* W" w" @3 J" b
54
3 T+ u& A# r6 S2 z1 S( Z( [55     return 0;
. p3 k# X+ `* r% x56 #endif  + E  J; n! h0 B; B
57 }
* \: @8 t" H# F+ n; _( m3 x; X. q8 a. x& _0 j+ J  |* j! o9 S9 t, f

$ g$ h1 O5 g5 |8 K
( Z1 Y& B* d( r8 G: ]5 E编译并执行:: W4 o. @" V6 I
' t5 C7 h+ l! z- a4 T# D, Q4 q
1 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c -lrt
/ T; M* g/ o. F6 D% x6 U. _' E1 C2 root@linux:/mnt/hgfs/C_libary# ./crtmq
8 }) l" ]/ E* P3 程序并没有删除消息队列(消息队列有随内核持续性),如再次执行该程序则会给出错误信息: 6 d# w" ?; U2 G- Y4 h
4 root@linux:/mnt/hgfs/C_libary# ./crtmq ) l* ?5 y# T! D- P
5 创建MQ失败: File  exit(0)
  Y, r# }: F  O- Z4 [- q& T
+ k# _; `  \9 f, i: S! s$ Q5 n
( n5 u' f; l1 y  r5 K向消息队列写消息的程序:% ?; r0 m' J5 u5 o3 ~7 V1 `4 o

, \" Z6 U5 V9 A% c4 i/ g# M
  • 消息队列的读写主要使用下面两个函数:
  • /*头文件*/
  • #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 */
  • };
    ) i- K7 |& C& r
* ]7 r( P6 p$ y  ~) S; Z, O2 J1 E

) c1 Q" k" a/ ?) P; D' @
7 Z8 V/ L$ E# c! n9 t+ \2 f; P5 `. }- M2 Y4 G9 U3 O- h$ [
7 B( y" ]" g8 Y  n2 z$ @  C7 G& ^
1 #include <stdio.h>  
7 r( Y" Y6 Y, k, r/ w0 F 2 #include <stdlib.h>  9 @) d' ]& Q8 T8 h  p" {
3 #include <mqueue.h>  * O# t& l5 P- V* j. \
4 #include <sys/types.h>  
) k3 K0 t$ Y! J( m% a5 r 5 #include <sys/stat.h>  2 [' Q  }* k1 f* y: h7 S
6 #include <unistd.h>  
: H* m, P+ v8 t& t% |- k 7 #include <fcntl.h>  
" }5 O0 c: @" @' W  w. z' j! S" w 8 #include <errno.h>  
) _$ \6 w! \7 P. D 9    8 o6 u- p) C: a( z) f# V. Q
10 /*向消息队列发送消息,消息队列名及发送的信息通过参数传递*/
$ P! {% q( @9 X+ t11 int main(int argc, char *argv[])  
$ c' A/ F" F, X7 K0 |7 s( r: _12 {  
$ m# n* g; R  m' _: r$ ^13     mqd_t mqd;  1 b+ F1 F2 |+ W' c# c4 d  v
14     char *ptr;  
% `( x# Q0 p; o- @: W& `15     size_t len;  5 }0 ^) S0 f/ E' ^
16     unsigned int prio;  
" Y( _. q5 s5 V- a17     int rc;  
2 }$ Z5 D7 m" J1 c2 g: D# D( p18 - M7 Z) ^: g, t+ G& W- I
19     if(argc != 4)  % u: t& e* G3 v/ ~4 Y
20     {  
! j* d1 i# z2 x/ x6 i. S21         printf("Usage: sendmq <name> <bytes> <priority>\n");  6 R) G; k! B/ O2 o
22         exit(1);  
* p# }( Z$ E' V" C- a6 T. B23     }  
4 y* @8 y7 L" z* u24 - \2 `% A) P+ r5 z9 \/ A
25     len = atoi(argv[2]);  
& D! `; A; }5 b4 A+ }/ Z; T26     prio = atoi(argv[3]);   
- w; U7 Z! i4 E( L0 g4 y; B27
5 i, `' |4 a- a8 f28     //只写模式找开消息队列  
6 M) H! ?+ R( B& {29     mqd = mq_open(argv[1], O_WRONLY);  
! i, y& Y, F% w30     if(-1 == mqd)  
8 W' q/ m% J" d* M; p31     {  6 N! t+ R, v2 P
32         perror("打开消息队列失败");  3 M0 G9 Y# t9 f$ g/ F+ u
33         exit(1);    ]6 ]0 h5 }; h4 U/ k* K
34     }  ' ~: ^2 s+ ^, \; M1 t8 {9 I$ Q
35 # @8 W3 j2 P' Y( Q; I# P
36     // 动态申请一块内存  & u# o) O* C5 g9 [+ D; X; ^0 c2 b
37     ptr = (char *) calloc(len, sizeof(char));  
5 h, e0 H$ ?6 j9 u$ d- A0 _3 j38     if(NULL == ptr)  ' u: O0 X# P9 s( E/ H1 ~/ E* ~' y$ b; t
39     {  
- R- c6 a2 q  ^; C, J, c40         perror("申请内存失败");  1 C" P' m8 ]9 U7 @
41         mq_close(mqd);  
, [) e! S3 g# |% N' E42         exit(1);  
: ~0 V( ]! H8 Z. J% i: T# B/ R43     }  5 p" S7 c6 X: U; D8 r
44   
4 L2 d( ?: t* \7 a45     /*向消息队列写入消息,如消息队列满则阻塞,直到消息队列有空闲时再写入*/
& ^( L' `+ N) e! ^46     rc = mq_send(mqd, ptr, len, prio);  
* b4 Z1 C3 w9 s7 }8 c2 N47     if(rc < 0)  
, h4 y' X9 d0 x, c0 z. P6 _48     {  # C4 \  u1 ]+ t* G7 }: B
49         perror("写入消息队列失败");  
9 O" ?" J$ ~; U( U1 L50         mq_close(mqd);  : B; E( M3 d. u) D1 W3 q' K' i
51         exit(1);  
1 k4 h1 {$ I( r5 P52     }     - t8 O! ]4 p4 `. u5 d, z2 r8 R
53
& t/ Z% M: Q' C; e' B54     // 释放内存  " h8 R( |' T* g! V$ x5 N: \2 M9 q, x) T
55     free(ptr);  6 }5 U. N$ w! O0 H
56     return 0;  2 Z5 ^* p( j3 a/ \
57 }
3 T- j" k; ]1 ~" X' U
8 c) O% g' I: `, R8 {: `$ n+ _
) T5 g# n2 W2 @0 m) U编译并执行:
5 V. t* w6 K2 z+ s) y. f# k( w/ b4 \6 E' y7 V1 v# }
1 root@linux:/mnt/hgfs/C_libary# gcc -o sendmq sendmq.c -lrt
6 N! W5 B1 W8 @* q! i1 ~" b. ?2 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 15
9 o/ s; J* I  W% w) q  D! u3 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 16( |3 s1 y- _) T$ C& \, d1 N" ?  I. }
4 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 17
3 n; e8 D/ D1 ]$ ^/ s5 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 181 Q. S4 u8 s! y* x2 `; A1 {

: A+ f# U5 {  m8 F/ ~* D* m  上面先后向消息队列“/tmp”写入了四条消息,因为先前创建的消息队列只允许存放3条消息,本次第四次写入时程序会阻塞。直到有另外进程从消息队列取走消息后本次写入才成功返回。
1 J4 d( p5 O, P6 V0 Q- ]
" t" z0 D* o5 Y2 O8 g& _3 M4 f! o" U$ o( A& U

( M0 s. y  F( r; D读消息队列:
' ?. h" s+ r2 f* F/ E( ]0 W" W8 _+ B8 k3 G2 y$ v/ o* H
#include <stdio.h>  , j% P# W" U% V: K2 E
#include <stdlib.h>  " Y2 A3 Y: ~& c& o
#include <mqueue.h>  - M" ]7 j4 c1 Y6 Q) E8 w0 ?
#include <sys/types.h>  8 O, w6 ]: W  X& g2 e# }8 L5 E
#include <sys/stat.h>  
* c7 x& s! I4 r#include <unistd.h>  6 W: U4 G5 `7 q  b; c
#include <fcntl.h>  / I$ {$ {- |* k! V
#include <errno.h>  
! r. F% ]8 ]  h9 x- a1 ]* ^7 [1 ]- s& X+ `) x
/*读取某消息队列,消息队列名通过参数传递*/
# W8 B  C+ G" W( w  B' d; _9 z( }  @: Uint main(int argc, char *argv[])  7 _3 o* o  d& l& f. e% P
{  
) O9 ~$ x  I3 C    mqd_t mqd;  
, k! r: [. C5 f' m4 m    struct mq_attr attr;  
' ?* `! t2 d; E0 c( @    char *ptr;  
( S, w4 W; x( `9 D    unsigned int prio;  
4 a9 W* n0 @3 O    size_t n;  
% K$ L# ?- I5 P: H1 U% O    int rc;  
/ b' U( C2 {( r$ i$ B6 N- b# x/ u: h
    if(argc != 2)  # i8 p. H8 o: b) n$ }
    {  ' x9 k' V+ C) _( j
        printf("Usage: readmq <name>\n");  + @* f/ d. f% a
        exit(1);  
. e& t" z) _' J1 i4 i+ C    }  
5 `! i' Y% E# ^; ^1 D4 C6 {. l  L" F7 i& V! L" _+ [: l( Q
    /*只读模式打开消息队列*/
1 W, _4 X  Z5 n& y" |# |. `    mqd = mq_open(argv[1], O_RDONLY);  
) P" w$ t4 f' p- i: b4 |9 [    if(mqd < 0)  8 v. [! X% z8 Q6 Q1 F
    {    B: v0 H  x- E5 A0 C( J
        perror("打开消息队列失败");  
( E8 p7 C6 \4 D9 A3 Y/ i% W% K# ]        exit(1);  
& F( @4 _5 h& p$ r9 @    }     ; V8 F9 \: h" u6 v% \

6 D( N" f& `, d4 s" i/ |    // 取得消息队列属性,根据mq_msgsize动态申请内存  
5 r3 E* q4 X# I; G. Y# [    rc = mq_getattr(mqd, &attr);  1 t1 w8 @: D2 o, v
    if(rc < 0)  # u2 c+ A7 g  W' G, M2 Z# N
    {  
! ?) {# [: c  A) }. G3 S        perror("取得消息队列属性失败");  
0 ~+ u* N8 a5 ]6 m6 I7 W8 U8 m        exit(1);  8 Q( c# Y% z8 O7 y: U4 R
    }  " @( z3 T6 ~" m6 w. q' w1 Q
( K0 e- `' g, y5 d/ s7 o
    /*动态申请保证能存放单条消息的内存*/
  n! ?0 E" |9 n4 X    ptr = calloc(attr.mq_msgsize, sizeof(char));  : X# Q  b3 D) v* }) o
    if(NULL == ptr)  , i6 J6 I4 j& n8 Y+ n
    {  
/ N7 ^* `: O& I2 c$ T- @4 D1 e3 P        printf("动态申请内存失败\n");  
1 g5 g. Z. ]- i: j7 v        mq_close(mqd);  
: A3 Q% _( W6 t, y/ u2 e# W; [; U/ O        exit(1);  / i1 N; |2 U" [% g
    }     
) f- G- P5 U: u" O
$ ~2 s( G; ?$ A" F" r3 Q& m$ ~- J, R, S    /*接收一条消息*/ - d, ^5 g2 \# C0 q6 U4 x  F
    n = mq_receive(mqd, ptr, attr.mq_msgsize, &prio);  + s3 q6 d, ?) P9 }, F7 _
    if(n < 0)  
; D: _( {& x& h% v    {    L7 E! x( Q! T3 P1 Z& p5 _7 q
        perror("读取失败");  ! H2 K$ j! R# G% u0 o
        mq_close(mqd);  
1 E- V. {3 P8 g& D        free(ptr);  
! h) J) f4 `* t& h" }        exit(1);  
* ]; h1 O' t  x5 p, `. }: j, z    }  
& ]6 U6 B! T2 l1 {7 ~( ?) e$ ^   
6 c8 \" c: T. u* l3 W) |    printf("读取 %ld 字节\n  优先级为 %u\n", (long)n, prio);     : }- e7 G! l6 m( H6 s, Q6 }8 O
    return 0;  ) {4 x/ i# M. v! Y8 C5 t4 b
} 9 q! d7 p1 ~* n/ |

( ]2 @# E0 c: E/ j4 z, x5 s" h. I% O' J

7 H, r7 y: i5 _: [* ]8 Q: i+ |% ^* e编译并执行:  w3 p$ G2 }4 T
( c& t- L/ R6 T5 @
1 root@linux:/mnt/hgfs/C_libary# vi readmq.c
8 A9 u4 s; D. N# Q. ~5 h 2 root@linux:/mnt/hgfs/C_libary# vi readmq.c
& J1 G  H1 t' F( J4 b/ {! B8 ~ 3 root@linux:/mnt/hgfs/C_libary# gcc -o readmq readmq.c -lrt- }# t9 ?# M5 a' _
4 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp( f* @$ ?# r7 v: U
5 读取 30 字节1 t9 E2 T% D( ?/ L! }6 q+ ?
6   优先级为 18
/ M. ^8 k3 ?( J 7 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp3 b+ [1 R6 G' l; j+ l3 N
8 读取 30 字节* C  |/ G# z3 I) O
9   优先级为 17
0 z* S3 K( Y; W+ M: a* s) o10 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp; J7 X; y. h3 z9 f* i2 ?* j# ~
11 读取 30 字节
/ m$ D# Q$ s. D0 @1 @; V8 d9 w. S12   优先级为 16
5 u2 C) ^- {3 Z$ M13 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp/ Q3 M1 C% I$ r( T/ c
14 读取 30 字节
: y) f( D* Q9 |% I+ Q15     优先级为 15
9 Q- ^  H. {4 x. T" h; d16 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
! u4 E* d( u0 ]# }1 b2 [- K, b3 i8 D1 X8 v" Y2 I1 K* [6 I
( ?" H! m3 D+ W# }* U* J
4 c. ~8 h$ v5 s3 @6 W: O
  程序执行五次,第一次执行完,先前阻塞在写处的程序成功返回。第五次执行,因为消息队列已经为空,程序阻塞。直到另外的进程向消息队列写入一条消息。另外,还可以看出Posix消息队列每次读出的都是消息队列中优先级最高的消息。
* k7 Y: k" F; x; k  j# F* b" Z2 v& n( ]8 e; z
$ p2 s: p6 R# r8 |1 ]

$ V+ i1 Y) i* ^+ K( rIPC通信:Posix消息队列的属性设置
2 K8 H2 S4 X+ \; g, u3 H
2 U5 B( x, y, T1 H
  • 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  v: B, r8 K/ Z- R  ]: q

( K* w- Z$ f$ Z, j4 a0 M
, W4 A0 X) Q1 {. `: y程序获取和设置消息队列的默认属性:  z7 L1 F0 g. N& j3 W1 k9 k! |; h
" G2 F+ j; \& E# Q
1 #include <stdio.h>  
2 }2 ~6 a9 m( Q3 }; u( T 2 #include <stdlib.h>  / _, u6 `; T) u" U. Z$ g4 i
3 #include <mqueue.h>  ( t2 g2 b/ ^+ z+ z1 n8 d2 \+ l
4 #include <sys/types.h>  $ Q/ [( y  E$ H! N' i/ }' Q
5 #include <sys/stat.h>  
( I7 W+ ~' \$ I- f6 H 6 #include <unistd.h>  
$ I% b" N' g1 P, Q0 S 7 #include <fcntl.h>  * w  X, \4 t% L! P; u0 W
8 #include <errno.h>  1 ]9 u7 e  d- \6 S
9   
7 Q& w! k" h9 }. f2 P10 #define MQ_NAME ("/tmp")  
7 v' \' P- V! r" C8 l9 U3 h* Y11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag  
/ ]- {+ D7 k6 }7 I' l12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限  * w- s0 B" M8 [; k! Y$ s+ S/ O
13    " ~( H4 ~4 I6 O
14 int main()  
4 U- z) ]+ \9 K2 ?15 {  . b( Q+ Q& K$ X& ?4 H% f
16     mqd_t posixmq;  5 C& p+ v* s- {
17     int rc = 0;  9 c( N( @" r% x# I6 _+ ]7 @) V% c# m
18   
! D7 j) u  ~) {, Q9 O6 B8 s19     struct mq_attr mqattr;  
* |, A6 f1 P9 R, i& X  G20   
* L8 T9 |; E/ ^: x4 N' E21     // 创建默认属性的消息队列  4 }& X- D$ `( u; n. u0 {+ w& d
22     posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);  % a( }  U+ v- a; j6 V  h# P9 o  b
23     if(-1 == posixmq)  4 k- ~" D* `5 S5 d; k; u
24     {  
- s: h0 w9 R5 f1 A; S: h: |25         perror("创建MQ失败");  
0 F. m: G, W  E7 Q26         exit(1);  + O; c% v$ v9 y+ z
27     }  : Z( n1 _* i3 {# F( W
28        & j2 Q! c8 @+ B$ S6 W& Q9 S# a1 H
29     // 获取消息队列的默认属性  ( c) Q* Z6 s. _' @% C: Z
30     rc = mq_getattr(posixmq, &mqattr);  
/ y% N, h  F! Y6 D/ [7 v31     if(-1 == rc)  8 D6 L3 s" v/ l5 h
32     {  # ^/ Y; d: ?- ^+ E
33         perror("获取消息队列属性失败");  - v2 T' a) V4 v/ ]( Q
34         exit(1);  9 ^8 }4 @( q7 G9 u' Z# E4 o1 C' x
35     }  
) ~; @# s, V5 n/ S0 [7 z36
5 A8 e$ r# [; j6 A# U) |! ]9 n37     printf("队列阻塞标志位:%ld\n", mqattr.mq_flags);  
* @) L/ q6 t9 N3 Y, ^) T% B8 j38     printf("队列允许最大消息数:%ld\n", mqattr.mq_maxmsg);  $ D% O2 y! f9 B
39     printf("队列消息最大字节数:%ld\n", mqattr.mq_msgsize);  
. ]9 x% x# P( u) B" u6 ]  j40     printf("队列当前消息条数:%ld\n", mqattr.mq_curmsgs);  
2 v- `. ?' @6 m* d0 C41    ( @0 f' R! a4 P) }  r. d6 e
42     rc = mq_close(posixmq);  & m  J' }3 z# t2 s" Q
43     if(0 != rc)  4 }& ]1 U  G# g7 Y  j! f
44     {  8 `- A! O/ ]9 t" [
45         perror("关闭失败");  ' B8 N& {9 S: E" |4 ?
46         exit(1);  : i6 O% w& }% T, }" i
47     }  . G! z$ g9 M+ u) v9 b9 _% Y
48   
$ _! C' l% v, B2 H$ Q9 E49     rc = mq_unlink(MQ_NAME);  
! n( r( l# D! n4 p5 v+ A( r& X50     if(0 != rc)  3 a! W! _6 Z. z: e% C( R- ]
51     {  
. z  {' W9 O% e& @5 U% k* Y52         perror("删除失败");  
: Q* y1 U* [( K+ I' {$ S53         exit(1);  . D& Z' x# v3 g9 P7 {- i, ]4 ?
54     }     
5 r" V7 E% L: ?, a8 Z55     return 0;  
7 D( R& R: M6 R56 }
+ {, V1 j+ X0 r4 n3 _0 K# Q; p  g; ?% V1 y( l7 V) E

( y3 S0 S1 O; N编译并执行:$ h4 {& J6 b6 Q$ Y5 u. ~5 Q

$ m! G! p0 B/ t5 t) W0 t1 root@linux:/mnt/hgfs/C_libary# gcc -o attrmq attrmq.c -lrt
7 \& e+ }: |9 c3 g' {7 ]2 root@linux:/mnt/hgfs/C_libary# ./attrmq1 }- A& k8 b% [( b/ v
3 队列阻塞标志位:0
' B3 `" ^" s, u( W9 G! K4 队列允许最大消息数:10
) Y2 k, l9 a3 V$ y2 c3 D4 Y/ E5 队列消息最大字节数:8192
* b; n* s) P3 _, h( x" m! n6 队列当前消息条数:0
; d* d9 t+ ]; e% B7 root@linux:/mnt/hgfs/C_libary# " e8 P4 ?; ~9 B% b- F( k, C( T- @
4 W( c% \4 T, ?* l+ x
) z: d2 Q' I1 U% v2 @# H
设置消息队列的属性:
9 W( z  b( C) Z; ?, G- Y( b% D, w# k
1 #include <stdio.h>  4 g( B& H" ?% F: N7 n' [7 Q
2 #include <stdlib.h>  
- h# h# B8 H; J 3 #include <mqueue.h>  1 d4 h( U# o3 U( _
4 #include <sys/types.h>  
: R+ @) T1 Q! I; X 5 #include <sys/stat.h>  " W$ X2 R/ x! r- ]& s& k
6 #include <unistd.h>  & X5 x0 A2 z+ a  a/ N5 V8 k
7 #include <fcntl.h>  9 z" B8 z& t, c0 \( m- e4 r8 ~
8 #include <errno.h>  
% C0 U/ `* O3 T) I' W 9   
* [8 e+ G1 D2 z7 L% j% i6 k! U! |: p" @10 #define MQ_NAME ("/tmp")  
" e3 a4 D6 B: F2 [" K11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag  & B4 y( S  t+ u
12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限  
, c8 h# O$ g! L( k13    & h! ]- T, [/ ^  m
14 int main()  
% {, \* C0 F9 v5 p! A9 ?15 {  
7 |0 U! C9 E; z. U& x' w1 h  o16     mqd_t posixmq;  
' Y- w& s( f4 c: X17     int rc = 0;  - [+ A* M$ G/ C% q% N
18   
! }% b4 M# J. h+ a. s9 w19     struct mq_attr mqattr;  + Z2 |+ V: e- @% Z$ T0 m+ @7 z
20   
( C9 H0 }5 Y+ D1 O) M3 `- i3 k21     // 创建默认属性的消息队列  
4 P# U; K- s) D; s: t5 Z22     mqattr.mq_maxmsg = 5; // 注意不能超过系统最大限制  
* l; O' \: B0 \) X5 R$ \1 ^5 D23     mqattr.mq_msgsize = 8192;  2 w+ |: x" C" y! c) L
24     //posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);  
5 W8 N( p: d, w! X3 Q  q7 R/ z25     posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, &mqattr);  
$ ?  }! m" |0 C, }) q( D26
3 V+ F3 P& ^$ [: u! w* C27     if(-1 == posixmq)  5 r* d/ R% V; H
28     {  $ O8 ^: }1 ?$ U! C7 T8 l
29         perror("创建MQ失败");  
$ U. E& C0 d. n30         exit(1);  ) G: G" t  _- }0 u$ A6 P& s
31     }  9 e1 V$ ^4 e& Y
32     5 D' S2 j. g) W& x. i
33     mqattr.mq_flags = 0;  + g  M/ x. @% b' Q1 }' L
34     mq_setattr(posixmq, &mqattr, NULL);// mq_setattr()只关注mq_flags,adw  
( _$ \5 _$ J: u' g, w( E) {- L35          b# V1 ?6 c0 L- P) j' o* U
36     // 获取消息队列的属性  0 d/ _: }6 i% U3 A9 F9 a# v/ F
37     rc = mq_getattr(posixmq, &mqattr);  
5 c( S$ z" j+ P: S8 J1 j. g( w38     if(-1 == rc)  
  @. V+ s8 {& ^* i  p" h& k39     {  
3 [, y7 p1 o4 d8 t40         perror("获取消息队列属性失败");  
# G0 Y% G/ F. B+ H2 P* v1 f41         exit(1);  7 a/ N5 D% p6 ~% Q+ D/ [1 `
42     }  & Q1 S8 J; k1 k) B+ ^  \5 l0 o
43 ) u' I% F# Y9 c+ e" E/ L% y& E
44     printf("队列阻塞标志位:%ld\n", mqattr.mq_flags);  7 N+ G2 J6 |, ]- \3 f
45     printf("队列允许最大消息数:%ld\n", mqattr.mq_maxmsg);  
% p; W- Z4 T% P46     printf("队列消息最大字节数:%ld\n", mqattr.mq_msgsize);  
9 \8 {( ]8 c1 V5 t( M9 H47     printf("队列当前消息条数:%ld\n", mqattr.mq_curmsgs);  
+ J% K6 C+ I, y$ a/ M. v1 E48    2 f4 j4 F$ J- ^8 V
49     rc = mq_close(posixmq);  
% f9 }  Z  P: |  i50     if(0 != rc)  
7 w) u% b' u) a1 @, z9 L3 b- P51     {    j1 B2 M6 v: L( q7 q
52         perror("关闭失败");  # A7 c, m. M$ h2 g# l; s
53         exit(1);  
  _3 Q# K) i/ p. H  z5 F$ n54     }   
' W! G: {3 \" I) I  ], [1 Z) D55
+ z( ^0 U' r2 F56     rc = mq_unlink(MQ_NAME);  
! ?. Y% W3 f. r  v2 M& T) X) n0 s6 V57     if(0 != rc)  5 l+ ]; B! E, q, U. v  ^; c
58     {  
8 n; X5 J# U- k0 K, h59         perror("删除失败");  - K! j1 _0 ^1 P+ Y  F
60         exit(1);  
: M' t$ i) W# V8 V. V, B! z61     }' @+ s1 a8 b) h" o
62         
$ t9 {# t8 h8 P0 r, b/ `; \+ Z63     return 0;  6 M% K3 V7 |, L! @
64 } & W* @! h3 _1 m9 y# y) b# L, |

) s; q+ E( b4 u: u9 I
2 n: W4 E/ ~/ i4 }( e编译运行:5 i, @/ L+ w- C! w  V; m) O+ j

% e8 G: R: s+ e9 Z) ~0 b1 root@linux:/mnt/hgfs/C_libary# gcc -o setattrmq setattrmq.c -lrt# Q( ?" P0 }0 D: F- p9 |& Y
2 root@linux:/mnt/hgfs/C_libary# ./setattrmq
8 J4 x) N2 Y4 K( Q, {6 R3 队列阻塞标志位:0
+ W3 @' Z3 y* g& b, t4 队列允许最大消息数:5" N) r  C4 ~6 ^7 y) d3 ?
5 队列消息最大字节数:81927 N1 g. ], l) I: r; \
6 队列当前消息条数:09 K/ M2 H0 Y* L9 E
7 q& h9 R; G  Y2 f4 ?% N/ ^

) R! D$ J5 P) I
3 ?! h; d+ f1 n: S; f' ]7 g+ _- I) M! b. t7 J( w
, T6 ~. f' R( d" h' l6 D/ C3 K! n
9 b1 ]3 B' P; k# y

; Y6 T) v! F! S! w1 l+ a: H, A3 f! t+ }8 r. Q3 r; L
7 C! P0 f! u) w; Z% [$ D
. a% r6 F2 k# S
0 ?: R4 |! ^+ s9 ?

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

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

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

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

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