进程通信之消息队列(IPC)

cpp 复制代码
#include <iostream>
#include<string.h>
#include<unistd.h>

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


using namespace std;

/*
消息队列就是一个消息的列表,用户可以在消息队列中添加消息、读取消息等.

消息队列的使用包括如下4步骤:

1.创建或打开消息队列
    int msgget(key_t key, int flag);
        key : IPC_PRIVATE(每次用IPC_PRIVATE操作时,共享内存的key都一样,都是0)或ftok的返回值,只要key值是一样的,通过这个函数打开,则会对内核的同一个IPC对象操作
        flag:
              同open函数的权限位,也可以用8进制表法,IPC_CREA|0666
              IPC_CREAT‌:不存在时创建,存在时返回标识符
              IPC_CREAT|IPC_EXCL‌:确保创建新区段,已存在则失败
        成功 :消息队列ID
        出错 :-1

2.添加消息
    int msgsnd(int msqid, const void *msgp, size_t size, int flag);
        msqid:消息队列的ID
        msgp:指向消息的指针。常用消息结构
            struct msgbuf{
                long mtype;          //消息类型
                char mtext[N]};   //消息正文
            }
        size:发送的消息正文mtext的字节数
        flag:
            IPC_NOWAIT,非阻塞添加消息,如果队列满了,直接返回
            0:阻塞方式添加消息,如果队列满了,就阻塞,直到消息添加成功
        成功:0
        出错:-1

3.读取消息
    int msgrcv(int msgid,  void* msgp,  size_t  size,  long msgtype,  int  flag);
        msqid:消息队列的ID
        msgp:接收消息的缓冲区
        size:要接收的消息的字节数
        msgtype:
             0:接收消息队列中第一个消息。
            大于0:接收消息队列中第一个类型为msgtyp的消息
            小于0:接收消息队列中类型值不大于msgtyp的绝对值且类型值又最小的消息
        flag:
            0:若无消息函数会一直阻塞
            NOWAIT:若没有消息,进程会立即返回ENOMSG
        成功:接收到的消息正文的长度
        出错:-1

4.控制消息队列
    int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );
        msqid:消息队列的ID
        cmd:
            IPC_STAT:读取消息队列的属性,并将其保存在buf指向的缓冲区中。
            IPC_SET :设置消息队列的属性。这个值取自buf参数。
            IPC_RMID:从系统中删除消息队列,此cmd时第三个参数buf可为NULL
        buf : 消息队列缓冲区
        成功:0
        出错:-1

notice:
    1.多个进程同时访问消息队列时会产生竞态状态,必须使用信号量等同步机制来保证操作互斥

ipcs 命令:
ipcs -q:显示消息队列基本信息
ipcs -q -l:显示消息队列限制信息
ipcs -q -i msgid:查看指定消息队列的详细信息
ipcs -q -i 12124195 命令显示:
Message Queue msqid=0
uid=1000	gid=1000	    cuid=1000	cgid=1000	mode=0666
cbytes=0	qbytes=16384	qnum=0	   lspid=12239	lrpid=12238
send_time=Sat Nov 29 22:13:44 2025
rcv_time=Sat Nov 29 22:13:44 2025
change_time=Sat Nov 29 22:12:20 2025
*/

#define TYPE_A 100
#define TYPE_B 200
#define LEN 64
#define MSGPATH "."

typedef struct
{
    long mtype;
    char mtext[LEN];
} MSG;
#define TXT_LEN (sizeof(MSG) - sizeof(long))


int getMsgId()
{
    int msgid;
    key_t key;
    if ((key = ftok(MSGPATH, 'm')) < 0)
    {
        perror("fail to ftok");
        exit(-1);
    }

    if ((msgid = msgget(key, IPC_CREAT|0666)) < 0)//创建或打开消息队列
    {
        perror("fail to msgget");
        exit(-1);
    }
    printf("msgid=%d\n",msgid);
    return msgid;
}

int testWrite()
{
    int msgid = getMsgId();
    while (true)
    {
        printf("input send TYPE_A msg : ");
        MSG buf;
        memset(&buf,0,sizeof(MSG));
        fgets(buf.mtext, LEN, stdin);
        buf.mtype = TYPE_A;
        msgsnd(msgid, &buf, TXT_LEN, 0);//添加TYPE_A消息
        if (strncmp(buf.mtext, "quit", 4) == 0)
        {
            msgctl(msgid, IPC_RMID, NULL);//从系统中删除消息队列
            break;
        }

        printf("input send TYPE_B msg : ");
        memset(&buf,0,sizeof(MSG));
        fgets(buf.mtext, LEN, stdin);
        buf.mtype = TYPE_B;
        msgsnd(msgid, &buf, TXT_LEN, 0);//添加TYPE_B消息
        if (strncmp(buf.mtext, "quit", 4) == 0)
        {
            msgctl(msgid, IPC_RMID, NULL);//从系统中删除消息队列
            break;
        }
    }
    return 0;
}

int testRead()
{
    int msgid = getMsgId();
    while (true)
    {
        MSG buf;
        memset(&buf,0,sizeof(MSG));
        if(-1 == msgrcv(msgid, &buf, TXT_LEN, TYPE_A, 0))//读取消息
        {
            printf("recv message error\n");
            break;
        }
        if (strncmp(buf.mtext, "quit", 4) == 0)
        {
            break;
        }
        printf("recv TYPE_A from message queue : %s", buf.mtext);
        memset(&buf,0,sizeof(MSG));
        if(-1 == msgrcv(msgid, &buf, TXT_LEN, TYPE_B, 0))//读取消息
        {
            printf("recv message error\n");
            break;
        }
        if (strncmp(buf.mtext, "quit", 4) == 0)
        {
            break;
        }
        printf("recv TYPE_B from message queue : %s", buf.mtext);
    }
    return 0;
}


int main(int argc ,char**argv)
{
    if(argc > 1)
        testWrite();
    else
        testRead();
    return 0;
}
相关推荐
老鱼说AI1 小时前
算法基础教学第一步:数据结构
数据结构·python·算法
Jing_Rainbow2 小时前
【LeetCode Hot100 刷题日记(19/100)】54. 螺旋矩阵 —— 数组、矩阵、模拟、双指针、层序遍历🌀
算法·面试·程序员
地平线开发者3 小时前
征程 6 | linear 高精度输出配置方式
算法·自动驾驶
小尧嵌入式3 小时前
C++基础语法总结
开发语言·c++·stm32·单片机·嵌入式硬件·算法
white-persist3 小时前
【攻防世界】reverse | IgniteMe 详细题解 WP
c语言·汇编·数据结构·c++·python·算法·网络安全
稚辉君.MCA_P8_Java3 小时前
Gemini永久会员 归并排序(Merge Sort) 基于分治思想(Divide and Conquer)的高效排序算法
java·linux·算法·spring·排序算法
地平线开发者3 小时前
征程 6 | QAT 新版 qconfig 量化模板使用教程
算法·自动驾驶
多恩Stone3 小时前
【ModelScope-1】数据集稀疏检出(Sparse Checkout)来下载指定目录
人工智能·python·算法·aigc
山峰哥4 小时前
沉浸式翻译插件深度评测:打破语言壁垒的黑科技利器
数据结构·科技·算法·编辑器·办公