消息队列
# 消息队列
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法,该数据块可以被认为带有一个类型,接收进程可以独立接收不同类型的数据块。 每个数据块都有一个最大长度的限制,系统中所有队列包含的全部数据块的总数也有限制。
# 消息队列相关函数
# msgget函数
该函数用于创建一个新的或打开一个已经存在的消息队列。
#include <sys/tpyes.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int msgget(key_t key, int msgflg);
1
2
3
4
2
3
4
key
:和其他IPC机制一样,程序必须提供一个键值来命名某个特定的消息队列。msgflg
:由权限位组成,可以与IPC_CREAT
标识相或- 返回值:调用成功返回正整数的队列标识符。失败返回-1。
# msgsnd函数
该函数用来向消息队列中添加一条消息。
- 消息的长度必须小于系统规定的上限。
- 消息必须以一个长整型成员变量开始,接收函数将用这个变量来确定消息的类型。
#include <sys/tpyes.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int msgsnd(int msgid, const void* msg_ptr, size_t msg_sz, int msgflg);
1
2
3
4
2
3
4
msgid
:msgget
函数返回的消息队列标识符。msg_ptr
:指向准备发送消息的指针,消息以一个长整型成员变量开始。msg_sz
:消息的长度,不包括长整型消息类型成员变量的长度。msgflg
:控制当消息队列满或队列消息到达系统上限时发生的事情。IPC_NOWAIT
:函数立刻返回,不发出消息;否则进程挂起等待消息队列腾出可用空间。
# msgrcv函数
该函数用来从消息队列中读取一条消息。
#include <sys/tpyes.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int msgrcv(int msgid, void* msg_ptr, size_t msg_sz, long int msgtype, int msgflg);
1
2
3
4
2
3
4
msgid
:msgget
函数返回的消息队列标识符。msg_ptr
:指向准备接收消息缓冲区的指针,消息以一个长整型成员变量开始。msg_sz
:消息的长度,不包括长整型消息类型成员变量的长度。msg_type
:接收优先级。如果值为0,即取出消息队列中的第一个消息;如果为正数,将取出具有相同消息类型的消息;如为负数,将取出消息类型小于或等于msg_type
绝对值的第一个消息。msgflg
:控制当当前消息队列中没有相应类型消息可以接收时发生的事情。IPC_NOWAIT
:函数立刻返回,返回值为-1;否则进程挂起以等待一条对应消息的到来。- 返回值:成功时函数返回放到接收缓冲区中的字节数,消息被拷贝到由
msg_ptr
指向的用户分配的缓存区中,然后删除消息队列中的对应消息,失败返回-1.
# msgctl函数
该函数作用与共享内存的控制函数 (opens new window)很相似。
#include <sys/tpyes.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int msgctl(int msgid, int command, struct msgid_ds* buf);
1
2
3
4
2
3
4
- 成功返回0,失败返回-1。
- 如果删除消息队列时,一个进程正在
msgsnd
或msgrcv
函数中等待,则这两个函数将失败。
# 消息队列举例
编写两个程序,receive.c用于接收消息,send.c用于发送消息。
允许两个程序创建消息队列,但只有接收者在接收完最后一个消息之后可以删除它。
# 接收者代码
// receive.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct my_msg_st
{
long int my_msg_type;
char some_text[BUFSIZ];
};
int main()
{
int running = 1;
int msgid;
struct my_msg_st some_data;
long int msg_to_receive = 0;
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if (msgid == -1)
{
fprintf(stderr, "msgget failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
while(running)
{
if (msgrcv(msgid, (void *)&some_data, BUFSIZ,
msg_to_receive, 0) == -1)
{
fprintf(stderr, "msgrcv failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
printf("You wrote: %s", some_data.some_text);
if (strncmp(some_data.some_text, "end", 3) == 0)
{
running = 0;
}
}
if (msgctl(msgid, IPC_RMID, 0) == -1)
{
fprintf(stderr, "msgctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 发送者代码
// send.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MAX_TEXT 512
struct my_msg_st
{
long int my_msg_type;
char some_text[MAX_TEXT];
};
int main()
{
int running = 1;
struct my_msg_st some_data;
int msgid;
char buffer[BUFSIZ];
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if (msgid == -1)
{
fprintf(stderr, "msgget failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
while(running)
{
printf("Enter some text: ");
fgets(buffer, BUFSIZ, stdin);
some_data.my_msg_type = 1;
strcpy(some_data.some_text, buffer);
if (msgsnd(msgid, (void *)&some_data, MAX_TEXT, 0) == -1)
{
fprintf(stderr, "msgsnd failed\n");
exit(EXIT_FAILURE);
}
if (strncmp(buffer, "end", 3) == 0)
{
running = 0;
}
}
exit(EXIT_SUCCESS);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
编辑 (opens new window)
上次更新: 2023/03/31, 22:34:04
- 01
- Linux系统移植(五)--- 制作、烧录镜像并启动Linux02-05
- 03
- Linux系统移植(三)--- Linux kernel移植02-05