进程控制和通信(三)

消息队列

消息队列是在内核空间开辟的一块共享内存, 类似于以下结构:

https://z3.ax1x.com/2021/04/23/cXVKj1.png

内核提供共享区域做IPC

类似于具名管道, 消息队列也有一个标识符MSG_KEY, 用来标识不同的消息队列. 只要知道某个消息队列的标识符, 并且拥有相应的权限, 就可以使用相应的消息队列. 所以, 消息队列可以在没有亲缘关系的进程间使用.

Linux系统调用为我们提供了几个C接口用于消息队列, 在sys/msg.h可以找到定义. 主要是以下4个函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
/* Message queue control operation.  */
extern int msgctl (int __msqid, int __cmd, struct msqid_ds *__buf) __THROW;
/* Get messages queue.  */
extern int msgget (key_t __key, int __msgflg) __THROW;
/* Receive message from message queue.
   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern ssize_t msgrcv (int __msqid, void *__msgp, size_t __msgsz,
                       long int __msgtyp, int __msgflg);
/* Send message to message queue.
   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern int msgsnd (int __msqid, const void *__msgp, size_t __msgsz,
                   int __msgflg);
  • msgget接收MSG_KEY和权限flag, 用于创建或者打开一个消息队列.
  • msgsnd接收msg_id和消息内容以及消息控制flag, 用于发送消息.
  • msgrcv接收msg_id和接收消息的容器以及消息控制flag, 用于接收消息.
  • msgctl接收msg_id和控制命令, 用于控制消息队列.

bits/ipc.h可以找到各种flag:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
/* Mode bits for `msgget', `semget', and `shmget'.  */
#define IPC_CREAT	01000		/* Create key if key does not exist. */
#define IPC_EXCL	02000		/* Fail if key exists.  */
#define IPC_NOWAIT	04000		/* Return error on wait.  */

/* Control commands for msgctl',semctl’, and shmctl'. */ #define IPC_RMID 0 /* Remove identifier. */ #define IPC_SET 1 /* Setipc_perm’ options. /
#define IPC_STAT 2 /
Get `ipc_perm’ options. */
#ifdef __USE_GNU

define IPC_INFO 3 /* See ipcs. */

#endif

接下来, 我们开启两个进程, 使用消息队列实现进程间通信, 一个用于发送消息, 一个用于接收消息.

发送端

 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
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define MSG_KEY 7777

struct MSG {
long type;
char msg[1024];
};

int main() {
int msg_id = msgget(MSG_KEY, IPC_EXCL);
if (msg_id < 0)
{
msg_id = msgget(MSG_KEY, IPC_CREAT | 0666);
}

if (msg_id &lt; 0)
{
    printf("get msg queue failed!");
    return -1;
}
printf("msq key %d id %d\n", MSG_KEY, msg_id);

while(1)
{
    struct MSG msg;
    printf("msg type: ");
    scanf("%ld", &amp;msg.type);
    printf("msg info: ");
    scanf("%s", &amp;msg.msg);
    int snd_id = msgsnd(msg_id, &amp;msg, sizeof(msg.msg), IPC_NOWAIT);
    if (snd_id &lt; 0)
    {
        printf("send msg failed with errno=%d[%s]\n", errno, strerror(errno));
		msgctl(msg_id, IPC_RMID, 0);
        return -1;
    }
}

}

发送端定义了#define MSG_KEY 7777, MSG_KEY可以是任意的KEY, 不要和已有的混淆即可. 在创建消息队列的时候加了额外的权限, msgget(MSG_KEY, IPC_CREAT | 0666);, 6对应的是0110表示read和write. 在发送消息的时候, 如果发送失败, 则会移除对应的消息队列msgctl(msg_id, IPC_RMID, 0);.

此外, 我们还定义了一个结构体用来作为消息容器:

1
2
3
4
struct MSG {
    long type;
    char msg[1024];
};

第一个成员是long型, 作为消息的ID, 这意为着在同一个消息队列中, 每条消息都可以拥有不同的消息ID. 所以仅使用一个消息队列, 也可以在多个进程间实现通信, 且多个进程可以互不干扰.(关于这一点, 继续看后面的接收端就清楚了)

启动发送端程序, 输入消息ID和消息内容:

1
2
3
4
5
msq key 7777 id 1
msg type: 1
msg info: hello
msg type: 2
msg info: helloworld

接收端

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值