消息队列 | 青训营笔记

107 阅读2分钟

消息队列

1. 消息队列介绍

1.1 消息队列概念

消息队列是一种进程间通信或同一进程的不同线程间的通信方式。消息队列是消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

1.2 消息队列特点

  • 消息队列是面向消息的,而不是面向字节流的。
  • 消息队列可以独立于发送者和接收者存在,从而实现了空间解耦。
  • 消息队列提供了一种异步的通信协议,降低了系统的耦合度。
  • 消息队列提供了一种缓冲机制,使得消息的发送和接收不必同时发生。

1.3 消息队列优点

  • 解耦:允许独立的进程或线程在不需要知道彼此的存在的情况下通信。
  • 削峰:接收消息的进程或线程可以以自己的速度来处理消息。
  • 管理:消息队列提供了一个可管理的缓冲区,允许发送者发送消息,而不必等待接收者处理。
  • 异步通信:消息队列是异步的,发送者不必等待接收者处理消息。
  • 灵活性:消息队列提供了灵活性,允许在消息的开始和结束之间插入新的消息。

1.4 消息队列缺点

  • 消息队列的实现和维护比较复杂,需要引入新的组件。
  • 消息的内容必须事先定义好,接收方必须能够识别消息内容。
  • 消息队列的使用增加了系统的复杂性。

1.5 消息队列应用场景

  • 两个进程间通信
  • 两个线程间通信
  • 一个进程中的两个线程间通信

2. 消息队列实现

2.1 消息队列数据结构

消息队列是一个消息链表,每个消息都有一个消息类型,消息类型是一个整数,消息的数据部分可以是任意类型的数据。

struct msgbuf {
    long mtype;       /* message type, must be > 0 */
    char mtext[1];    /* message data */
};

2.2 消息队列操作

  • 创建消息队列:int msgget(key_t key, int msgflg);
  • 发送消息:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
  • 接收消息:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
  • 控制消息队列:int msgctl(int msqid, int cmd, struct msqid_ds *buf);

2.3 消息队列实例

2.3.1 创建消息队列

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

#define MSG_FILE "/etc/passwd"
#define BUFFER 255

struct msg_form {
    long mtype;
    char mtext[BUFFER];
};

int main()
{
    int msqid;
    key_t key;
    struct msg_form msg;
    
    if ((key = ftok(MSG_FILE, 'z')) < 0) {
        perror("ftok error");
        exit(1);
    }
    
    if ((msqid = msgget(key, IPC_CREAT|0777)) == -1) {
        perror("msgget error");
        exit(1);
    }
    
    printf("Open queue %d\n", msqid);
    printf("Please input the message to queue:");
    scanf("%s", msg.mtext);
    msg.mtype = 888;
    
    if (msgsnd(msqid, &msg, sizeof(msg.mtext), 0) == -1) {
        perror("msgsnd error");
        exit(1);
    }
    
    printf("The message is sent\n");
    return 0;
}

2.3.2 接收消息

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

#define MSG_FILE "/etc/passwd"
#define BUFFER 255

struct msg_form {
    long mtype;
    char mtext[BUFFER];
};

int main()
{
    int msqid;
    key_t key;
    struct msg_form msg;
    
    if ((key = ftok(MSG_FILE, 'z')) < 0) {
        perror("ftok error");
        exit(1);
    }
    
    if ((msqid = msgget(key, IPC_CREAT|0777)) == -1) {
        perror("msgget error");
        exit(1);
    }
    
    printf("Open queue %d\n", msqid);
    
    while (1) {
        msgrcv(msqid, &msg, BUFFER, 0, 0);
        printf("The message from process %ld : %s", msg.mtype, msg.mtext);
    }
    
    return 0;
}

2.3.3 控制消息队列

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

#define MSG_FILE "/etc/passwd"
#define BUFFER 255

struct msg_form {
    long mtype;
    char mtext[BUFFER];
};

int main()
{
    int msqid;
    key_t key;
    struct msg_form msg;
    
    if ((key = ftok(MSG_FILE, 'z')) < 0) {
        perror("ftok error");
        exit(1);
    }
    
    if ((msqid = msgget(key, IPC_CREAT|0777)) == -1) {
        perror("msgget error");
        exit(1);
    }
    
    printf("Open queue %d\n", msqid);
    
    msgctl(msqid, IPC_RMID, NULL);
    
    return 0;
}