头图

前言

最近要搞个功能,涉及到了进程间通信,最后商定用消息队列的方式。先回顾下消息队列的特点:

  • 队列结构: 先进先出(FIFO)的数据结构
  • 消息类型:可以传递不同类型的消息,这些消息可以是文本、二进制数据或自定义数据结构
  • 异步通信: 允许发送方和接收方以异步方式进行通信。发送方将消息放入队列后可以立即继续执行,而不必等待接收方的响应
  • 解耦应用程序:有助于解耦不同组件或模块之间的通信,这意味着它们可以独立开发、部署和扩展,同时仍能相互通信
  • 可靠性:一些消息队列系统提供了消息持久化功能,确保即使在系统故障或重启后,消息也不会丢失
  • 多对多通信:多个发送方可以将消息发送到同一个队列,多个接收方也可以从同一个队列接收消息,这种多对多通信模型非常灵活

介绍

编程步骤

  • 头文件:<sys/types.h>、<sys/ipc.h> 和 <sys/msg.h>。
  • 创建消息队列:msgget
  • 定义消息结构
  • 发送消息:msgsnd
  • 接收消息:msgrcv
  • 关闭和删除消息队列:msgctl

msgget

  • 函数:int msgget(key_t key, int msgflg);
  • 功能:创建并打开消息队列
  • 参数:msgflg:IPC_CREAT, IPC_EXCL

    • IPC_CREAT :

      • 如果消息队列对象不存在,则创建之,否则则进行打开操作;
    • IPC_EXCL:

      • 和IPC_CREAT 一起使用(用”|”连接),如果消息对象不存在则创建之,否则产生一个错误并返回。
      • 如果单独使用IPC_CREAT 标志,msgget()函数要么返回一个已经存在的消息队列对象的标识符,要么返回一个新建立的消息队列对象的标识符。
      • 如果将IPC_CREAT 和IPC_EXCL标志一起使用,msgget()将返回一个新建的消息对象的标识符,或者返回-1 如果消息队列对象已存在。I
      • PC_EXCL 标志本身并没有太大的意义,但和IPC_CREAT 标志一起使用可以用来保证所得的消息队列对象是新创建的而不是打开的已有的对象。
  • 返回:成功返回消息队列的ID(非负数),失败-1

msgsnd

  • 函数:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
  • 功能:向一个消息队列发送消息
  • 参数:

    • msqid :指定访问的消息队列
    • msgp :要发送的消息(消息类型,消息内容)
    • msgsz :消息中消息内容的大小
    • msgflg:0阻塞模式,IPC_NOWAIT非阻塞模式
  • 返回:成功返回0,失败-1

msgrcv

  • 函数:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
  • 功能:从消息队列中接收一条消息
  • 参数:

    • msqid :指定访问的消息队列
    • msgp :要发送的消息(消息类型,消息内容)
    • msgsz :指定消息中消息内容的大小
    • msgflg:0阻塞模式,IPC_NOWAIT非阻塞模式
    • msgtyp:

      • =0:接收第一条消息
      • \>0:读取指定类型中的第一条
      • <0:小于等于msgtyp中最小类型的第一条消息
  • 返回:成功返回接收到的消息内容字节数,失败-1

msgctl

  • 函数 :int msgctl(int msqid, int cmd, struct msqid_ds *buf);
  • 功能:控制消息队列(获取信息,设置, 删除)
  • 参数:

    • IPC_RMID //删除消息队列,buf忽略
    • IPC_STAT //获取消息队列状态
    • IPC_SET //设置消息队列
  • 返回:成功返回0 失败返回-1

ftok

  • 函数:key_t ftok(const char *pathname, int proj_id);
  • 功能:获得一个key值,同于访问一个确定的消息队列、共享内存、信号灯
  • 参数:pathname已存在的文件名, id是子序号,它是一个8bit的整数。即范围是0~255, proj_id非0的整数
  • 返回:成功返回key,失败-1

示例

发送方

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


struct msgbuf{
    long mtype;
    int a;
    float b;
    char c;
};

#define N sizeof(struct msgbuf) - sizeof(long)

int main(int argc, const char *argv[])
{
    struct msgbuf msgbuf;

    //获取key值
    key_t key = ftok(".", 1);

    //创建并打开消息队列,成功返回消息队列的id
    int msgid = msgget(key, IPC_CREAT|0664);   //不存在则创建,存在的话打开,创建的权限是0664
    if(msgid == -1)
    {
        perror("msgget error");
        exit(1);
    }

    //发送消息 
    msgbuf.mtype = 1;
    msgbuf.a = 10;
    msgbuf.b = 10.23;
    msgbuf.c = 'A';
    msgsnd(msgid,  &msgbuf, N, 0);

    msgbuf.mtype = 2;
    msgbuf.a = 20;
    msgbuf.b = 20.23;
    msgbuf.c = 'B';
    msgsnd(msgid,  &msgbuf, N, 0);

    msgbuf.mtype = 3;
    msgbuf.a = 30;
    msgbuf.b = 30.23;
    msgbuf.c = 'C';
    msgsnd(msgid,  &msgbuf, N, 0); //均发送到消息队列中。

    return 0;
}

接收方

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

struct msgbuf{
    long mtype;
    int a;
    float b;
    char c;
};

#define N sizeof(struct msgbuf) - sizeof(long)

int main(int argc, const char *argv[])
{
    //获取key值
    key_t key = ftok(".", 1);  //相同的文件的键值是相同的

    //创建并打开消息队列
    int msgid = msgget(key, IPC_CREAT|0664);
    if(msgid == -1)
    {
        perror("msgget error");
        exit(1);
    }

    //接收消息
    struct msgbuf msgbuf;
    msgrcv(msgid, &msgbuf, N, -2, 0);
    printf("a = %d  b = %.2f  c = %c\n",msgbuf.a,  msgbuf.b,  msgbuf.c);
    
    //删除
    system("ipcs -q");
    msgctl(msgid, IPC_RMID, NULL); //删除消息队列
    system("ipcs -q");

    

    return 0;
}
欢迎关注个人博客沟通交流

NULL
30 声望0 粉丝