通过消息队列进行通信(嵌入式学习)

通过消息队列进行通信

概念

在Linux中,消息队列是一种进程间通信(IPC)机制,用于在不同进程之间传递数据。它提供了一种异步通信的方式,允许一个进程将消息放入队列,而另一个进程可以从队列中获取消息。

消息队列由内核维护,每个消息都有一个关联的标识符,用于在进程之间进行识别和传递。进程可以使用系统调用函数操作消息队列,这些函数包括创建队列、发送消息、接收消息和删除队列等。

IO间进程通信请点击这里——》IO进程间的通信详解(嵌入式学习)
IO进程间的通信详解(嵌入式学习)《——这里
IO进程间的通信详解(嵌入式学习)《——这里这里里
IO进程间的通信详解(嵌入式学习)《——这里里里里

消息队列的概念包括以下几个重要组成部分:

  1. 队列:消息队列是一个按照特定顺序组织的消息集合。它可以被多个进程共享,并且可以容纳多个消息。

  2. 消息:消息是进程之间传递的数据单元。消息可以包含不同的数据类型,如整数、字符串等。每个消息都有一个特定的类型,以便接收进程能够正确解析和处理它。

  3. 发送进程:发送进程是将消息放入队列的进程。它通过指定目标队列和消息内容来发送消息。

  4. 接收进程:接收进程是从队列中获取消息的进程。它可以选择从特定队列接收消息,并根据需要处理接收到的消息。

  5. 阻塞和非阻塞操作:在发送和接收消息时,进程可以选择阻塞或非阻塞操作。阻塞操作会使进程暂停等待,直到发送或接收操作完成。非阻塞操作允许进程继续执行其他任务,而不必等待操作完成。

使用消息队列可以实现进程之间的解耦和异步通信。它适用于需要在不同进程之间传递数据的场景,例如多个进程共同处理一个任务、进程间的事件通知和进程间的数据共享等。

特点

Linux中消息队列具有以下特点:

  1. 异步通信:消息队列提供异步通信机制,发送进程将消息放入队列后即可继续执行其他任务,而不需要等待接收进程处理消息。这样可以提高系统的并发性和响应性能。

  2. 独立性:消息队列的发送进程和接收进程是相互独立的,它们可以以不同的速度进行消息的发送和接收。发送进程和接收进程可以存在于不同的时间和空间上,甚至可以是不同的计算机系统。

  3. 顺序性:消息队列保持消息的顺序性,即按照发送的顺序将消息放入队列,并按照相同的顺序进行接收。这样可以确保消息的有序传递,使得接收进程能够按照正确的顺序处理消息。

  4. 缓冲能力:消息队列可以作为一个缓冲区,可以容纳多个消息。即使发送进程发送消息的速度快于接收进程处理消息的速度,消息队列也能够缓冲未被接收的消息,避免消息的丢失。

  5. 多对多通信:消息队列支持多对多的通信模式,即多个发送进程可以同时向同一个队列发送消息,多个接收进程可以从同一个队列接收消息。这样可以实现灵活的进程间通信模式。

  6. 持久性:消息队列可以具有持久性,即在消息发送完成后,消息可以保留在队列中,直到被接收进程读取。这样可以确保即使接收进程暂时不可用,消息也不会丢失。

  7. 基于标识符:每个消息在队列中都有一个唯一的标识符,用于在进程之间进行识别和传递。发送进程可以指定目标队列和消息内容,接收进程可以选择从特定队列接收消息。

这些特点使得消息队列成为一种强大的进程间通信机制,在分布式系统、多进程协作和异步任务处理等场景中得到广泛应用。

函数

在Linux中,可以使用以下函数来操作消息队列:

  1. msgget():创建或获取一个消息队列。它接受一个键值和标志作为参数,并返回一个与该键值关联的消息队列标识符。

  2. msgctl():控制消息队列。它可以用于删除队列、获取或设置队列的属性等。需要指定消息队列标识符以及相应的命令参数。

  3. msgsnd():发送消息到队列中。它需要指定目标队列的标识符、消息指针、消息长度和消息类型等参数。可以选择阻塞或非阻塞方式发送消息。

  4. msgrcv():从队列中接收消息。它需要指定源队列的标识符、消息指针、消息长度、消息类型和接收标志等参数。可以选择阻塞或非阻塞方式接收消息。

这些函数都是通过系统调用来实现的,需要包含 <sys/msg.h> 头文件。

以下是一个简单的使用消息队列的示例代码:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>

struct message {
    
    
    long mtype;
    char mtext[100];
};

int main() {
    
    
    key_t key;
    int msgid;
    struct message msg;

    // 生成一个唯一的键值
    key = ftok("msgq_example", 'A');

    // 创建或获取消息队列
    msgid = msgget(key, IPC_CREAT | 0666);
    if (msgid == -1) {
    
    
        perror("msgget");
        return 1;
    }

    // 发送消息
    msg.mtype = 1;
    snprintf(msg.mtext, sizeof(msg.mtext), "Hello, message queue!");
    if (msgsnd(msgid, &msg, sizeof(msg.mtext), 0) == -1) {
    
    
        perror("msgsnd");
        return 1;
    }

    // 接收消息
    if (msgrcv(msgid, &msg, sizeof(msg.mtext), 0, 0) == -1) {
    
    
        perror("msgrcv");
        return 1;
    }

    printf("Received message: %s\n", msg.mtext);

    // 删除消息队列
    if (msgctl(msgid, IPC_RMID, NULL) == -1) {
    
    
        perror("msgctl");
        return 1;
    }

    return 0;
}

这个示例程序创建了一个消息队列,并发送一条消息到队列中,然后从队列中接收一条消息并打印出来。最后,删除消息队列。

示例代码

下面是一个使用消息队列进行进程间通信的示例代码,其中一个进程负责发送消息,另一个进程负责接收消息:

Sender(发送进程)

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>

struct message {
    
    
    long mtype;
    char mtext[100];
};

int main() {
    
    
    key_t key;
    int msgid;
    struct message msg;

    // 生成一个唯一的键值
    key = ftok("msgq_example", 'A');

    // 创建或获取消息队列
    msgid = msgget(key, IPC_CREAT | 0666);
    if (msgid == -1) {
    
    
        perror("msgget");
        return 1;
    }

    // 准备要发送的消息
    msg.mtype = 1;
    strncpy(msg.mtext, "Hello, receiver!", sizeof(msg.mtext));

    // 发送消息
    if (msgsnd(msgid, &msg, sizeof(msg.mtext), 0) == -1) {
    
    
        perror("msgsnd");
        return 1;
    }

    printf("Message sent: %s\n", msg.mtext);

    return 0;
}

Receiver(接收进程)

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>

struct message {
    
    
    long mtype;
    char mtext[100];
};

int main() {
    
    
    key_t key;
    int msgid;
    struct message msg;

    // 生成一个唯一的键值
    key = ftok("msgq_example", 'A');

    // 获取消息队列
    msgid = msgget(key, 0666);
    if (msgid == -1) {
    
    
        perror("msgget");
        return 1;
    }

    // 接收消息
    if (msgrcv(msgid, &msg, sizeof(msg.mtext), 0, 0) == -1) {
    
    
        perror("msgrcv");
        return 1;
    }

    printf("Message received: %s\n", msg.mtext);

    return 0;
}

以上代码中,Sender进程通过消息队列向Receiver进程发送一条消息。首先,两个进程使用相同的键值获取消息队列的标识符。Sender进程使用msgsnd()函数发送一条带有消息类型1的消息,而Receiver进程使用msgrcv()函数接收消息类型为0的消息。最后,Receiver进程将接收到的消息打印出来。

在运行示例代码之前,请确保在同一个目录下同时编译并运行Sender和Receiver进程。

猜你喜欢

转载自blog.csdn.net/m0_56694518/article/details/131275602