EDA365电子论坛网
标题:
IPC通信:Posix消息队列
[打印本页]
作者:
mytomorrow
时间:
2021-4-26 17:10
标题:
IPC通信:Posix消息队列
* R9 b* f( o! ^
消息队列可以认为是一个链表。进程(线程)可以往里写消息,也可以从里面取出消息。一个进程可以往某个消息队列里写消息,然后终止,另一个进程随时可以从消息队列里取走这些消息。这里也说明了,消息队列具有随内核的持续性,也就是系统不重启,消息队列永久存在。
; P, G$ U0 ^2 X. q% }9 S6 U- l
8 L% [1 C& o$ l6 o- g# A
创建(并打开)、关闭、删除一个消息队列
0 P R: e" x* v- m4 X
5 v ]3 j3 e& P6 J
1 #include <stdio.h>
. t" Z8 i5 D J5 O+ C& q
2 #include <stdlib.h>
. b1 l! d* s" s
3 #include <mqueue.h> //头文件
1 ~& g+ a) x0 T5 r' q2 j0 n9 p
4 #include <sys/types.h>
: I9 r: v2 a5 D& u0 T! N3 ]6 x& m
5 #include <sys/stat.h>
' ?* \: R- R R
6 #include <unistd.h>
$ D2 M ~ }; f$ J. D% { k
7 #include <fcntl.h>
: B* @8 D* p6 E0 b% m7 O J
8 #include <errno.h>
+ ^8 W0 w9 y9 v- S, m; m
9
2 C% H, a# v2 \! M, l6 T
10 #define MQ_NAME ("/tmp")
6 @# g/ J5 b+ v. C) l2 p+ G: e: r
11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag
& G3 X9 U( S, B% ~& P+ F
12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限
+ {9 e( D7 }6 G" P( E D
13
. V% H9 e2 d3 i3 L8 k/ L9 [) w. W
14 int main()
, l5 X" Y- ?' ~, w' o: {
15
! B- N4 H$ }2 |3 \- W& u% d- m m
16 {
. z0 ^2 R2 V0 Y/ i1 e5 `! @
17 mqd_t posixmq;
$ {0 D! q0 R( J o* L
18 int rc = 0;
$ j8 R2 V7 H: K+ s. u7 @
19
/ |& E" g6 f* s* A4 Y+ P
20 /*
9 L7 L8 |2 u5 x7 v& B& Z
21 函数说明:函数创建或打开一个消息队列
9 g) ?; Z/ s. E! b) ^- y }
22 返回值:成功返回消息队列描述符,失败返回-1,错误原因存于errno中
: u8 C1 i: i- u$ |6 \0 d4 J4 O
23 */
1 b" e. H: V6 I) \- Q. a4 o
24 posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);
: V2 v' u! U) J- @6 m; m
25
6 N# a6 G3 l' X# p- d8 _$ [- H9 r5 ^
26 if(-1 == posixmq)
- @% W4 o X- Y% k3 s! s+ `; P
27 {
2 l! @! t; n) Q
28 perror("创建MQ失败");
P$ ~0 T. T0 R5 n/ d0 e1 W3 |: o
29 exit(1);
8 V9 M% s6 a- Q' Y, f, s
30 }
5 ^: ]% f8 x A
31
}# l% v: k" o
32 /*
" \. Z* }; ]3 X+ W$ j/ P
33 函数说明:关闭一个打开的消息队列,表示本进程不再对该消息队列读写
# G& e x' O/ z
34 返回值:成功返回0,失败返回-1,错误原因存于errno中
, z! A# ^7 M0 w8 P
35 */
+ y$ [* k4 I; O! v' R# E
36 rc = mq_close(posixmq);
) \" a% G# b* T1 Q& w/ G
37 if(0 != rc)
- M3 y5 F: }4 B$ z: p, k9 n
38 {
3 O2 h, T, {0 a9 a" F3 ^
39 perror("关闭失败");
: q# Q' H- `7 H4 u' g
40 exit(1);
' Y* C) r0 S p' |
41 }
9 [4 Z, j5 M3 A' c6 ~% _
42
" s/ v: K+ N7 h6 ^
43 /*
) r: i3 F1 }& l/ @1 O: ^
44 函数说明:删除一个消息队列,好比删除一个文件,其他进程再也无法访问
) b: Q- h. O# E- p( k! q
45 返回值:成功返回0,失败返回-1,错误原因存于errno中
/ s4 s% I+ H6 w6 i+ W+ l
46 */
* E- I2 i: i0 C" ]# W2 @
47 rc = mq_unlink(MQ_NAME);
: Q- _8 C0 m0 h! Q/ o% d
48 if(0 != rc)
7 o; ?. _" G: E" r) [! d6 \3 G
49 {
7 L9 J0 _, i' G$ z
50 perror("删除失败");
, H3 e/ V) x- c7 B
51 exit(1);
2 q6 c- L& i/ o! I' ?; M
52 }
5 L$ l' ^. t" p3 J
53
8 X }; Z; `9 K+ u
54 return 0;
1 N! Z7 ~' O; N% m! \' C
55 }
- D/ F1 U4 B% X1 E" U
3 {( M) ?0 Z8 t- l W4 G" k- n: H
) S: @9 _( |2 w
编译并执行:
" d/ \, X/ R! m" ?. n
8 m/ I( a D) U4 O
1 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c
- f0 E' s! j) E- K( t' ^6 T' A
2 /tmp/ccZ9cTxo.o: In function `main':
1 t) {% F& f8 |- ~! H( c; s
3 crtmq.c:(.text+0x31): undefined reference to `mq_open'
5 k( l; { G5 {; {$ Q; U4 v& k
4 crtmq.c:(.text+0x60): undefined reference to `mq_close'
. E( ` z- R, V4 H3 J
5 crtmq.c:(.text+0x8f): undefined reference to `mq_unlink'
4 v. T( P- N4 ~
6 collect2: ld returned 1 exit status
8 L1 |+ l' O( [6 x1 R7 C8 k: F
7 因为mq_XXX()函数不是标准库函数,链接时需要指定;库-lrt;
- b6 J3 J& ^( f1 b. O
8 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c -lrt
6 }0 I; F# F6 G! O& j
9
* P7 @, `( r# e$ T
10 root@linux:/mnt/hgfs/C_libary# ./crtmq
( q# _. k$ S9 t, J% t* Q; @
11 最后程序并没有删除消息队列(消息队列有随内核持续性),如再次执行该程序则会给出错误信息:
6 A$ U8 @ J0 i7 p, R, g
12 root@linux:/mnt/hgfs/C_libary# ./crtmq
$ S& H( h, [/ s
13 创建MQ失败: File exit(0)
3 ]3 s# k# n$ c& O" X
$ U% m( Y) E/ @/ W n" [
7 E$ h9 v- j; w2 H3 w
3 p! B' [3 `4 S' b0 K( r
编译这个程序需要注意几点:
. h+ a H( l' ~1 [4 i6 B8 k
5 U8 H6 G- ~! r3 d; k \; H9 b
1、消息队列的名字最好使用“/”打头,并且只有一个“/”的名字。否则可能出现移植性问题;(还需保证在根目录有写权限,为了方便我在root权限下测试)
8 b2 y+ C8 h: e; ~* Q$ S) Q' j
2、创建成功的消息队列不一定能看到,使用一些方法也可以看到,本文不做介绍;
. _. @7 H: ?" e( r( L3 z
4 u9 `& f& n$ z2 {& |$ G2 l
消息队列的名字有如此规定,引用《UNIX网络编程 卷2》的相关描述: mq_open,sem_open,shm_open这三个函数的第一个参数是
& O4 b1 i4 N$ |
一个IPC名字,它可能是某个文件系统中的一个真正存在的路径名,也可能不是。Posix.1是这样描述Posix IPC名字的。
6 |6 ]: p2 B9 ^+ Z$ }% J1 q
1)它必须符合已有的路径名规则(最多由PATH_MAX个字节构成,包括结尾的空字节)
# [3 ?4 x e* l0 J" t" H/ f
2)如果它以斜杠开头,那么对这些函数的不同调用将访问同一个队列,否则效果取决于实现(也就是效果没有标准化)
8 d1 \! o# J' k; z" [8 B6 f; U5 @
3)名字中的额外的斜杠符的解释由实现定义(同样是没有标准化) 因此,为便于移植起见,Posix IPC名字必须以一个斜杠打头,并且不能再包含任何其他斜杠符。
) H# e# R, o8 G$ r
" S% R& V! f5 S' ~0 f& I( O
c' q1 ]* K- o; y
IPC通信:Posix消息队列读,写
6 y9 u# t3 Z* F& [
0 L; S' h8 G" ]4 ]3 ^! ~7 n
创建消息队列的程序:
$ l; V- @: ]+ i# Q9 A% B& l) M5 D
+ l* j' ?; ~. O# E* {
1 #include <stdio.h>
+ k9 z: W3 a9 w W7 Q" F
2 #include <stdlib.h>
9 H3 O( k s X
3 #include <mqueue.h> //头文件
" N6 P3 v2 {; f5 Y2 m, q
4 #include <sys/types.h>
( N' G' D+ D% W# a! ^
5 #include <sys/stat.h>
5 n& i4 {1 x8 ]- X9 Y4 ^5 \
6 #include <unistd.h>
, |4 B7 w" y, S8 L
7 #include <fcntl.h>
; n1 ?8 R! W* }. l" s9 J
8 #include <errno.h>
" ^, @% R0 h: q8 R" r( j5 g0 n
9
* v) Y$ L k. {. U4 N
10 #define MQ_NAME ("/tmp")
& P6 ]+ E L! k' ] ?# R
11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag
* \+ J8 M$ m1 ]
12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限
6 G* I6 g4 e. ]3 N# p7 U. l4 w
13
0 b. P- y2 n! d, m
14 int main()
5 @; H4 ~3 I# [+ C. o. S$ a7 [
15
8 e1 u& p) ]& r- o2 S M( o
16 {
w8 T! F+ @: E" A% O
17 mqd_t posixmq;
8 D& v f$ [; s1 p: e5 J! G
18 int rc = 0;
% @8 d* `% t0 @8 p
19
3 n. Q5 S" i$ P S0 m- O
20 /*
! o, `* p5 C9 H+ O3 ?+ D/ v
21 函数说明:函数创建或打开一个消息队列
6 p) }5 }1 c( j& D9 v W! u2 T
22 返回值:成功返回消息队列描述符,失败返回-1,错误原因存于errno中
& g* H! E+ I6 k' u, C4 {
23 */
3 Q4 i! _7 T) h& e
24 posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);
1 F+ i6 A- A2 `5 p7 D
25
/ ^- k+ x; |2 V& ?8 Z9 d7 l
26 if(-1 == posixmq)
7 C; F" g' s3 O. J. k
27 {
1 P& `1 m9 C& r" C* y) L
28 perror("创建MQ失败");
( B1 d8 m) l! o: `0 B
29 exit(1);
+ m3 C9 S9 ]) ? C: a. P
30 }
% a# f9 \% y0 D( X; P4 V
31
' j0 p& Y0 M8 I$ S! b
32 /*
1 e/ W% b* g# \+ [
33 函数说明:关闭一个打开的消息队列,表示本进程不再对该消息队列读写
/ g! B, `9 R4 ~
34 返回值:成功返回0,失败返回-1,错误原因存于errno中
+ j; I2 N2 f+ _5 t! |! K
35 */
* r8 }8 a7 d/ r' b" G8 d# j
36 rc = mq_close(posixmq);
; e+ K9 E0 h% l5 Z; ~- i. p, o6 e
37 if(0 != rc)
: D; x/ L% g+ d4 p3 r8 w
38 {
- R: B* r* o$ n! U" H9 O2 c, f
39 perror("关闭失败");
" k; H) I! i6 W/ Z, M
40 exit(1);
, t" X k* S: }& h' F. }
41 }
$ L) b5 }9 C7 M5 T ^, Z. i
42
W) q5 p( g+ S4 [# a$ T
43 #if 0
1 G+ u" \$ z1 ^! s: `
44 /*
5 p4 }0 y5 @8 m
45 函数说明:删除一个消息队列,好比删除一个文件,其他进程再也无法访问
8 n/ A0 F1 c, E9 A A0 {) O. g7 N* M
46 返回值:成功返回0,失败返回-1,错误原因存于errno中
% B& x' o/ T: D# }0 a3 c6 T. E
47 */
" B* U D& x3 Q& ^; b3 z! h
48 rc = mq_unlink(MQ_NAME);
# ?6 Z% g/ K+ ^9 ]
49 if(0 != rc)
$ z/ p* R# F: [/ k5 b( t5 i. @
50 {
0 {0 w% G, I, c& Z
51 perror("删除失败");
& w Z6 ]$ p" Q/ m# U
52 exit(1);
6 t. V! p$ J( K. d
53 }
0 j4 }& g" l, i/ t
54
6 C" b3 u. `! ~5 P: B4 [( F
55 return 0;
! l0 x7 U! l4 C* Q7 u% q" t4 p
56 #endif
2 U- J7 Q5 b' [1 C; P' s5 Z8 n
57 }
7 k! T1 x' V, n) }4 O5 x
0 _: j: @9 ]* B4 P R
& o! J8 e( r6 a) b4 Q% r2 \' r8 |
" H2 p, Z+ k8 f- S( Q
编译并执行:
% X! k. v! W8 w
/ {( E7 p, I) T
1 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c -lrt
$ e1 |5 P* z3 v; s. i
2 root@linux:/mnt/hgfs/C_libary# ./crtmq
- h$ K! c9 a" Y9 O- s) `- q, E
3 程序并没有删除消息队列(消息队列有随内核持续性),如再次执行该程序则会给出错误信息:
# h& R) w+ Z* z; S. V! B
4 root@linux:/mnt/hgfs/C_libary# ./crtmq
: R9 r% n) A* F( a. x# g- y* \7 n
5 创建MQ失败: File exit(0)
* D! F% ], \6 O; ` P
* S9 D3 D3 @$ k' ?( m B
$ s6 \; Y! C# V7 ]
向消息队列写消息的程序:
, h1 L# E8 D, D# F% M0 w, N
) S3 r: \8 o0 v- D3 e! r
消息队列的读写主要使用下面两个函数:
/*头文件*/
#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 */
};
9 Z6 Z' U' k5 X6 [- `0 E0 }
# o4 n, c% P! [, y4 Q: n8 V
& U. d4 f- V* l" L
, P) j, u, a4 @8 U. M' Z C
$ n$ z! E% z6 i' \( |5 a- ]
c- z8 u8 w, R4 a1 L k# J1 F
1 #include <stdio.h>
. V2 a) c! V" V' W
2 #include <stdlib.h>
* m9 \ T- W- ]- ?9 g I' B
3 #include <mqueue.h>
& u/ d* B$ P: a: k2 p% [6 [
4 #include <sys/types.h>
7 h6 U- n4 I( e' q* e
5 #include <sys/stat.h>
" _; h3 A2 n$ q9 I) t$ h
6 #include <unistd.h>
$ c$ n0 U/ N2 w* u) z% D3 J
7 #include <fcntl.h>
0 Y: P, X' T1 F( U0 g, T' ]
8 #include <errno.h>
o: e- R+ {; L5 ?) Q7 ~+ M
9
X- ^& c4 w$ ^, u) A. a0 v
10 /*向消息队列发送消息,消息队列名及发送的信息通过参数传递*/
9 s: }! w. F+ r% J
11 int main(int argc, char *argv[])
2 a& r0 Y$ c6 R
12 {
7 ? ^) J9 |; u7 {" d
13 mqd_t mqd;
& v7 O, X( M' E6 {2 A7 h$ z
14 char *ptr;
* M2 h( H9 C8 F; ~& ^6 J- m
15 size_t len;
& m4 @0 r/ z9 P5 P9 b: z
16 unsigned int prio;
3 H9 B! J, C2 E) e% B Q
17 int rc;
( u: Z, O5 ~) v! F( J
18
/ k3 n5 D }1 S; K6 p8 M1 ^' Z$ }
19 if(argc != 4)
2 p5 K$ Y1 ~9 g' U& ~3 Q4 D. d
20 {
' L: |: H/ Z0 m; b: f1 ^' @* V ?+ o# X5 W
21 printf("Usage: sendmq <name> <bytes> <priority>\n");
% V1 n) K0 k9 [7 b, Q, k
22 exit(1);
; P7 ~+ `( W. W! p; S+ O! E: F
23 }
9 c( }1 p3 y% i
24
9 r W% V* k2 Z' H; \
25 len = atoi(argv[2]);
* q/ s/ } O+ a0 H& W
26 prio = atoi(argv[3]);
I; }- h/ S" i8 Z& X" X$ [
27
, T; t+ `- t3 ?/ f
28 //只写模式找开消息队列
5 e- A) O: U: S0 u0 V0 U
29 mqd = mq_open(argv[1], O_WRONLY);
" P& m( f% v) {) |* Q/ E3 n
30 if(-1 == mqd)
, X8 ^, |+ Q1 G1 I
31 {
/ H" f0 x& B: A3 [, g; p3 l
32 perror("打开消息队列失败");
# S. T {' ? O
33 exit(1);
( }' n4 q' `7 h& b3 H+ m' U
34 }
1 T3 t9 j5 X% c+ R' W
35
2 U; z( W% V S- |' K
36 // 动态申请一块内存
. V- J S' A) V
37 ptr = (char *) calloc(len, sizeof(char));
5 O! t* p' l+ C! o3 O
38 if(NULL == ptr)
. ]1 K: m8 b. ^ U. J, n; _4 I; ?
39 {
+ r* n! j" S8 Q
40 perror("申请内存失败");
% K0 W/ _: F& y+ P6 Y1 B6 e
41 mq_close(mqd);
8 j& S2 @4 ?) y* H6 _
42 exit(1);
8 t0 [( b, ?. C" ]& ?7 Q/ A
43 }
: P5 Z" q& o# \
44
5 E$ Q/ O3 \3 f5 z
45 /*向消息队列写入消息,如消息队列满则阻塞,直到消息队列有空闲时再写入*/
1 o6 N. I" o, g0 P$ w/ K5 m7 l
46 rc = mq_send(mqd, ptr, len, prio);
. C6 V; u8 m1 C0 X1 m+ v# u+ T3 E
47 if(rc < 0)
: e7 ?, ^% _7 o3 t) |, ^! q
48 {
1 I2 ^2 E" N% S: t& |( b& \
49 perror("写入消息队列失败");
5 F; ~# ?0 g/ Q# _! g0 d7 ?
50 mq_close(mqd);
4 {3 g ?1 b9 \9 f" t: k
51 exit(1);
4 O6 Q/ y9 a: W
52 }
* C* @" K6 `7 _( G' V' j! b1 f
53
2 o, ^1 V! Y4 N; L E& Y3 A
54 // 释放内存
2 i5 W+ m. _8 q/ f" y
55 free(ptr);
; t4 S9 a1 e, H& s8 z1 C
56 return 0;
; u0 q; [$ Z9 Q: ?( T
57 }
. k9 C4 I7 L* k# X0 Y4 s; T4 Z
+ a+ r5 o: o" @% q p
* T' H( A) E T
编译并执行:
! o0 ]" _9 q) [
0 ^/ d9 O- I) r+ q6 d' d- F, I% r3 p
1 root@linux:/mnt/hgfs/C_libary# gcc -o sendmq sendmq.c -lrt
2 \& c% C E# R" z. V8 d. Y
2 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 15
; ]6 _ c& Q( q( m3 }8 x
3 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 16
- z/ W9 }+ J8 B
4 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 17
" Z* q& _( S% p1 Q4 p J3 g
5 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 18
* G% D7 {/ I, h
3 R; ?& k [+ S4 |! n
上面先后向消息队列“/tmp”写入了四条消息,因为先前创建的消息队列只允许存放3条消息,本次第四次写入时程序会阻塞。直到有另外进程从消息队列取走消息后本次写入才成功返回。
6 b- }$ P( X5 _; `$ h
3 Q& C. t% j- A/ [ N
! k8 I! B1 b! Y4 Q; u
) ?! H5 F" ? C/ g
读消息队列:
% i: t0 ^- o% W# ^ I
; `0 K& j4 s3 T
#include <stdio.h>
) M( E; Z" K( g u g- y! P
#include <stdlib.h>
& j; g. ^! P+ t" R& T3 K
#include <mqueue.h>
" m1 N& D7 R; i7 c" B7 Y
#include <sys/types.h>
. z3 u9 `8 O' {: n8 [
#include <sys/stat.h>
, {9 c* y! X& k; F3 ^, m
#include <unistd.h>
4 [* G, }! l$ R6 D* Q8 P6 n
#include <fcntl.h>
8 i# H% J4 O3 Q4 @+ |
#include <errno.h>
* b" L9 |: u/ s
8 g2 O" [4 V7 i2 X
/*读取某消息队列,消息队列名通过参数传递*/
7 y3 g; M) ?: f* t
int main(int argc, char *argv[])
# U4 r) G' h, C
{
+ {3 o! u- |! f4 o& _
mqd_t mqd;
3 y% @0 h6 y+ F: X2 ?
struct mq_attr attr;
! q* c6 f; H ^$ k) l0 [( J
char *ptr;
/ T+ l1 w- a" u) i& e) D4 V+ p
unsigned int prio;
$ I+ P5 |9 W1 \9 s1 Q
size_t n;
' r+ q6 |4 \" Q/ ?# I0 l
int rc;
' Z ~6 h4 r3 i2 a7 \& F
0 O+ z3 P# d4 R
if(argc != 2)
. b) Y, R: b" k0 n1 M
{
+ K4 o: b& s' ~5 ?8 k5 M
printf("Usage: readmq <name>\n");
# u& `- B; n$ p# H$ M2 @
exit(1);
3 E g3 k& x. r8 T9 C+ n2 u( A) i$ |
}
! d. d& V6 Q5 m2 p/ ]1 A% ?: {
5 M' n, B. \' c) h9 b! Y y
/*只读模式打开消息队列*/
6 R' w3 F( Z6 b4 Z
mqd = mq_open(argv[1], O_RDONLY);
' b. i5 Y7 U9 v T" E
if(mqd < 0)
* c5 R+ c0 y/ @+ x
{
% k0 R; ~% x0 e( B
perror("打开消息队列失败");
: n9 w! u0 R k5 W u* k
exit(1);
0 ^$ r5 j* w' s, t6 A+ h
}
% M C7 D$ a/ o& }% {7 D4 `. \6 @
0 O8 R- U' E! \$ [& V( M
// 取得消息队列属性,根据mq_msgsize动态申请内存
- w. b9 Q$ Q! o% J( T
rc = mq_getattr(mqd, &attr);
7 N% Y. { k2 Z0 ~
if(rc < 0)
* m6 |/ k+ H' `$ @! o. D) E. p. I
{
* m' Q7 f6 p1 I
perror("取得消息队列属性失败");
g7 z" o. Q1 h9 }/ q- b
exit(1);
* o5 f4 A4 E+ a" |
}
. g' ^6 n, L) O! E: E. n
# z$ _' |* A* J, @+ ^0 d
/*动态申请保证能存放单条消息的内存*/
$ ^ @* {' A( I3 ]1 L7 N
ptr = calloc(attr.mq_msgsize, sizeof(char));
! Q1 f$ n) m# _! Z3 @7 J
if(NULL == ptr)
& N @( Y' p( Q# Q) x" {
{
) `# {, _+ {0 a. G/ ]! {; r; u
printf("动态申请内存失败\n");
; j6 D" ]1 {' p9 E: a+ i
mq_close(mqd);
, g; T& ?0 i2 j/ _+ @8 j3 V A: k
exit(1);
1 ?7 d# o7 d5 @) O7 p0 O- E* A
}
$ p, l9 D. w c+ L
) v0 \3 K' E- K# s4 _
/*接收一条消息*/
( [6 k' z+ C k
n = mq_receive(mqd, ptr, attr.mq_msgsize, &prio);
$ T$ }! Q% ?: u! \
if(n < 0)
+ V" P% b( Q. \5 W, E: }
{
% R; X6 x" F9 X; v1 r2 S2 {
perror("读取失败");
' [( x1 U3 c8 d( M
mq_close(mqd);
* ?0 j% g0 b8 s4 G
free(ptr);
, v) |% z7 Z' w3 U
exit(1);
4 ^7 r/ `) v% N8 ~
}
1 {' Y2 v6 ^- l2 Z: @9 o
[$ y& w% _" K1 `9 \
printf("读取 %ld 字节\n 优先级为 %u\n", (long)n, prio);
+ }/ |5 @" G- _9 A$ d
return 0;
1 W; v8 r) O+ v
}
/ t' j9 y: t! {9 a/ X8 E* q# h$ Q
* e, w$ S) j- ?0 q; W3 k' h
+ y+ l9 O* v* b* C7 T- q1 s! @
6 Z( k1 B3 J; b
编译并执行:
$ s+ Z$ _5 i) m( _$ \9 ~
# E- o$ t4 k0 y
1 root@linux:/mnt/hgfs/C_libary# vi readmq.c
( l1 t8 |( W$ i- O/ Y' [. f& q
2 root@linux:/mnt/hgfs/C_libary# vi readmq.c
* v Y( W$ i. g1 ?
3 root@linux:/mnt/hgfs/C_libary# gcc -o readmq readmq.c -lrt
5 `; d( M u. c& P
4 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
( F8 H- M1 y& Q3 M* W
5 读取 30 字节
2 M9 B }! V4 O. h5 y- C
6 优先级为 18
' I6 a/ t# x G4 V$ w9 k0 f: r9 V
7 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
6 y: I+ B, L$ I4 N+ a a
8 读取 30 字节
5 t. v$ Y2 p1 ^3 Y* |% o
9 优先级为 17
% Y) B0 Y* f K* m# P
10 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
; |2 P M' Z* d2 z
11 读取 30 字节
% z2 [2 z- h0 ]9 P" T8 F, U: I$ |
12 优先级为 16
0 L7 [. C4 z$ I2 y1 ^1 W$ F
13 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
4 o3 [0 y- t5 t( T! c/ h+ B
14 读取 30 字节
' {' D8 Q' ?5 E( s8 H. a/ o
15 优先级为 15
8 Y6 b0 e3 |" c
16 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
9 r3 K. n! {/ |" n$ J1 t% B, H
, @* S. z- g$ O* o' K
6 Z% M I2 H! P# m
- q# P) }1 x5 O6 i3 h* r5 g- n2 N2 @
程序执行五次,第一次执行完,先前阻塞在写处的程序成功返回。第五次执行,因为消息队列已经为空,程序阻塞。直到另外的进程向消息队列写入一条消息。另外,还可以看出Posix消息队列每次读出的都是消息队列中优先级最高的消息。
# B" D9 G, p- j" n# }
. a" V. T+ }' r: L2 X' V
; G8 b, @7 m* y7 Y3 d
/ u5 v* m7 Z/ T
IPC通信:Posix消息队列的属性设置
1 T3 {" t5 D O. v( o" ^/ C
! G6 V+ d7 t8 }2 v* q+ D/ G
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 F! D! v& w! N* a3 z
1 y0 R# E8 Q/ R% ]9 Q8 A
+ u( z$ E9 O! l( U
程序获取和设置消息队列的默认属性:
- P8 C; e2 \. v. A* o4 a) V
8 g! f& x, G; J; m4 i% a/ O
1 #include <stdio.h>
+ W6 W, a$ [: B4 l
2 #include <stdlib.h>
; m0 V: B5 |0 a8 \
3 #include <mqueue.h>
" z. @9 _% f, {
4 #include <sys/types.h>
! a/ S1 { J C
5 #include <sys/stat.h>
B( Q+ N$ t1 F& v
6 #include <unistd.h>
4 u2 `: e! {3 ]
7 #include <fcntl.h>
6 h, X2 v. Q7 {+ p4 m
8 #include <errno.h>
+ o* H; b0 v, c7 K. n- V7 W
9
2 ]4 n) B4 ~( l$ k3 F
10 #define MQ_NAME ("/tmp")
5 {- o g- | \; S
11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag
, d! r) A. \" c5 f
12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限
: Y4 W( c# T) ?& d' Y' O
13
# z) G" `+ E, E3 Z; k7 m: s
14 int main()
7 R& h, T n+ x! n- N
15 {
& h ?0 b/ Y" B9 \: R
16 mqd_t posixmq;
9 b) Q5 c {0 f2 [( `" Y- h. [& a' h
17 int rc = 0;
1 [6 P. q* \% ]" |
18
- y' C- m, W) s" `$ r G9 f
19 struct mq_attr mqattr;
! h7 [4 u# @, l, H+ E5 e2 H9 m
20
* |) n# x) u& f" i6 S2 V, } P
21 // 创建默认属性的消息队列
$ J8 Z' w0 W0 n8 f* l5 X! F- H( B
22 posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);
% s- D4 B+ w6 O
23 if(-1 == posixmq)
$ }; i( @" ^' Q) w" c
24 {
0 S2 L5 W# S" F: H5 m
25 perror("创建MQ失败");
: _8 N+ s" W' J$ q6 o) ^2 O
26 exit(1);
n$ U% m1 i6 H) D
27 }
# I. @' F; j4 p
28
7 X4 Y. O% Q6 o _0 u
29 // 获取消息队列的默认属性
- `. o8 O+ C) ?
30 rc = mq_getattr(posixmq, &mqattr);
. {* w3 G; @& c8 N# Q$ S
31 if(-1 == rc)
" D5 T e, n" J0 k/ }
32 {
6 Q6 U) `' S; F1 S& K( Z( f+ J
33 perror("获取消息队列属性失败");
* Y+ ^; C; k- j: A) D
34 exit(1);
`* j# L$ F2 p& t1 [! q' k
35 }
1 x+ e5 |5 |4 l; A* i: s0 C) E
36
$ {" T0 F2 I8 z& O( K0 t5 c
37 printf("队列阻塞标志位:%ld\n", mqattr.mq_flags);
- D9 Z4 e) w9 b! Z! |9 e
38 printf("队列允许最大消息数:%ld\n", mqattr.mq_maxmsg);
# R( i: P- _& T. Z
39 printf("队列消息最大字节数:%ld\n", mqattr.mq_msgsize);
2 [3 X5 z9 s' G4 q" x1 A; O
40 printf("队列当前消息条数:%ld\n", mqattr.mq_curmsgs);
2 E9 M: V; g2 S3 m8 w
41
% E- V1 [" ~% w
42 rc = mq_close(posixmq);
* K' z, S9 q- N& g: C Y
43 if(0 != rc)
* \4 ]; X# X; S( c( r+ F
44 {
% l% A# H6 M/ a, ?
45 perror("关闭失败");
" z/ v& k9 G( T
46 exit(1);
" V. |0 | M) G, @
47 }
7 ]. _. Y, s/ j- d, n/ n( C. ?
48
6 E5 ^. f E" u0 V6 W. D
49 rc = mq_unlink(MQ_NAME);
8 o P9 E$ J4 Y% t- C+ L( k- q& N; W
50 if(0 != rc)
6 d9 U( p3 h+ w4 Q* r! h' c
51 {
/ ^/ v' J: q* k- O" W$ } X
52 perror("删除失败");
7 \; j6 q8 J, z$ r( _. Y& W
53 exit(1);
' ?. n# @7 v6 v1 }) o* q) y
54 }
% k% K( T" q: k& L I
55 return 0;
: c5 `3 K' E# M- |) I; |; @( ^
56 }
- r- o7 ~1 f& d d/ W- j- c9 q/ x
6 h$ l: s3 @$ P
) ]& _' S. ?2 ~ ~& R
编译并执行:
4 a) G9 g( X; O0 M& N
+ \" V3 ?7 O# r/ {. U6 E
1 root@linux:/mnt/hgfs/C_libary# gcc -o attrmq attrmq.c -lrt
% c& T# g9 e$ d" E% h) V4 C
2 root@linux:/mnt/hgfs/C_libary# ./attrmq
) c- j! h7 a1 I1 i
3 队列阻塞标志位:0
( C7 g0 f2 o2 x
4 队列允许最大消息数:10
. o" W" u! I+ c! F$ K: q
5 队列消息最大字节数:8192
$ B4 ]7 n/ @3 n" v' a, `
6 队列当前消息条数:0
. l4 x4 @& I/ B
7 root@linux:/mnt/hgfs/C_libary#
+ r- L" O. ?8 S
& i8 B* w7 q s$ M% M6 Y5 V
' S, o6 w6 \% m# s1 V m
设置消息队列的属性:
% q" }- D# D) V
( o0 M( I+ V3 k/ [
1 #include <stdio.h>
, ~! |, ~ Q* [& h& \ q
2 #include <stdlib.h>
! ~8 v% s1 \" Z# U7 z& {
3 #include <mqueue.h>
. R$ u% g5 l9 @ i) n
4 #include <sys/types.h>
* p c1 P7 T0 i% |' n/ R1 w
5 #include <sys/stat.h>
7 q/ L6 C) ^* @3 Q3 b) p( C
6 #include <unistd.h>
- z0 j, h, |3 a5 q7 j2 z
7 #include <fcntl.h>
: C7 ^" {( G+ h
8 #include <errno.h>
9 G) ?9 j) Q) j
9
9 p- ~5 ^3 V/ H1 e8 c9 [
10 #define MQ_NAME ("/tmp")
$ e% }, s; `; g: z( k" ?% `9 k
11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag
& J) @2 m! v- g- i; M2 [
12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限
' p9 m( Q' N: E6 E6 s/ n
13
- N$ u3 o0 W% l$ L/ Y6 K% m5 h$ P/ i
14 int main()
6 O! M# M/ t9 s( a1 ^( }% X
15 {
/ `' `: l" |* c/ [, b
16 mqd_t posixmq;
?2 |$ ]7 {2 A! [. }. u4 y1 t
17 int rc = 0;
: [* U3 G: w: @; d. [
18
: U8 B6 V1 W( B9 j% `5 Y
19 struct mq_attr mqattr;
# T; O, N3 r! _8 Y7 F9 h
20
4 O% n5 v6 } n0 u$ C( o
21 // 创建默认属性的消息队列
4 q. ]' ]: p3 y" {$ H
22 mqattr.mq_maxmsg = 5; // 注意不能超过系统最大限制
% r" Y/ J7 `" X, [" G( x. `* `
23 mqattr.mq_msgsize = 8192;
' Y+ F5 c1 `& [) ]
24 //posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);
4 x3 g* R; @" P# j0 r6 c& K% z" c
25 posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, &mqattr);
# F. P0 p0 {& L. T7 V
26
: g& Z9 ^6 ^3 ^
27 if(-1 == posixmq)
, e4 V q9 p4 y# W% t$ p
28 {
1 v% P$ D) M4 O* o5 A: \
29 perror("创建MQ失败");
' w# d6 X7 M1 Y& p/ i
30 exit(1);
, e3 _$ U1 U# J! [6 `; N4 h
31 }
6 P) U. J. N. P3 ]6 K
32
! b6 V, }( ?9 R% e! N: o9 s
33 mqattr.mq_flags = 0;
( `& h ?; ~4 `* h
34 mq_setattr(posixmq, &mqattr, NULL);// mq_setattr()只关注mq_flags,adw
- N" P7 `3 U3 R E; h. j5 I( M
35
5 f9 n, j: `0 X# s& T
36 // 获取消息队列的属性
/ d" n g/ g& p4 N' P8 q
37 rc = mq_getattr(posixmq, &mqattr);
$ N8 b: [( Y/ a4 A2 ?
38 if(-1 == rc)
" l2 R* y! D! @$ E
39 {
n9 B# T5 \$ [* a0 S" Z/ h& {3 e7 r
40 perror("获取消息队列属性失败");
1 A. ~. ~+ C" `( p6 C# E
41 exit(1);
" g/ t2 u A) G! E c& {: |8 E
42 }
2 q$ a1 d( _/ x/ R
43
' b0 L; B9 j! W3 \5 G$ S) ?
44 printf("队列阻塞标志位:%ld\n", mqattr.mq_flags);
# v& V, Y5 V6 s- c
45 printf("队列允许最大消息数:%ld\n", mqattr.mq_maxmsg);
$ F& a6 b# U6 ]4 B) H, a
46 printf("队列消息最大字节数:%ld\n", mqattr.mq_msgsize);
8 D. e9 m& { @: w" ]/ \- V. e* K4 v$ R
47 printf("队列当前消息条数:%ld\n", mqattr.mq_curmsgs);
\" v5 w( J* R
48
* k- v: u+ z9 N5 t- R
49 rc = mq_close(posixmq);
* m4 B/ ^* R8 |6 T
50 if(0 != rc)
6 h! {6 ^9 o3 X- z( Y0 l2 k
51 {
2 y z3 @5 U! g% Q0 y, [& B/ v* G5 T
52 perror("关闭失败");
9 \: ], M0 l* J7 E
53 exit(1);
\6 I2 y+ s# T. X0 D# a
54 }
( c8 V# `9 P. i( @1 y; o
55
8 B8 q9 H' ~( W
56 rc = mq_unlink(MQ_NAME);
" m3 B* Y& D) A" \: R1 @$ P/ f
57 if(0 != rc)
- d+ ?8 ^4 {+ r% C6 F
58 {
4 I5 K9 y6 j+ G' O6 c
59 perror("删除失败");
9 L: P# p7 k# G, F
60 exit(1);
" y2 b* T j" z6 D4 y
61 }
, O/ e( d# N) |( |
62
* U1 C6 O9 t# i& b
63 return 0;
$ D4 P& z4 A* s( l& z9 ?5 R. p: n
64 }
/ Q* J$ a+ a" G& u6 P
% `$ s6 `6 e' {! o! H! g0 d- ~$ ^; H" v% s
$ x; E) a% u: f4 ~
编译运行:
4 R( h2 a9 C. n2 \8 b
+ P' h3 n" a. a( x& q" Z
1 root@linux:/mnt/hgfs/C_libary# gcc -o setattrmq setattrmq.c -lrt
. L4 n/ m* ?* c2 S. @2 B. f, Y
2 root@linux:/mnt/hgfs/C_libary# ./setattrmq
$ `1 s! T; [( A
3 队列阻塞标志位:0
3 V4 b2 i6 }+ P5 v! r6 x
4 队列允许最大消息数:5
5 e! c% ~/ \' |7 b- U
5 队列消息最大字节数:8192
3 K% _: w4 V6 J7 R
6 队列当前消息条数:0
2 |0 E4 V# t. S' n5 A# ?: U
, f/ @1 j. k* h! T) L, x# f4 W* u
! G# h, k' E" M; G- M
7 o ~) u7 i0 V: N# Z+ d) I
" |" f" [ D" V
3 d1 ]1 B0 ^1 u# {& e, Q/ [: x* L
& k( q) a( s% Q% d9 I& `; J! i
8 ]! r k0 V0 b% f$ |
\5 r3 l5 }$ L- ?( _
, D- t7 A i7 I: c
3 y* o$ _& L. K/ }, a: ^
3 N4 _& ]8 A% D# u% M4 ]/ W
作者:
NNNei256
时间:
2021-4-26 17:55
IPC通信
osix消息队列
欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/)
Powered by Discuz! X3.2