Linux进程间通信 - - - 消息队列


前言

本文为笔者学习笔记,若有不妥之处,欢迎斧正。


一、消息队列概述

消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

消息队列的特点:

  1. 消息队列是面向记录的,其中消息具有特定的格式以及特定的优先级。
  2. 消息队列独立于发送和接受进程。进程终止时,消息队列的内容并不会被删除。
  3. 消息队列可以实现消息的随机查询,消息不一定要以先进先出的顺序读取,可以按照消息的类型读取。

进程间通过消息队列通信步骤:

  1. 创建或打开消息队列
  2. 添加消息
  3. 读取消息
  4. 控制消息队列。

二、消息队列相关API详解

1.获取键值

函数原型:

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

key_t ftok(const char *pathname, int proj_id);

函数作用:生成消息队列的键值(每一个消息队列都有一个对应的键值相关联,共享内存和信号量也需要)。

参数说明:

  1. pathname:路径名。
  2. proj_id:是0到25之间的值,可以随意取。

返回值:成功返回键值,失败返回-1。

2.打开或创建消息队列

函数原型:

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

int msgget(key_t key, int msgflg);

函数作用:创建或者打开消息队列。

参数说明:

  1. key:ftok函数返回的键值,也就是消息队列的键值。
  2. msgflg:需要的操作和权限,可以用来创建一个消息队列。

返回值:成功返回队列ID,失败返回-1。

3.添加消息

函数原型:

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

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

函数作用:添加消息。

参数说明:

  1. msgid:消息队列ID。
  2. msgp:消息结构体指针。
  3. msgsz:结构体中字符数组的大小。(发送可用sizeof或者strlen计算)
  4. msgflg:可以为0,也可以为IPC_NOWAIT。

返回值:成功返回0,失败返回-1。

4.读取消息

函数原型:

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

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);

函数作用:读取消息队列中的消息。

参数说明:

  1. msgid:消息队列ID。
  2. msgp:消息结构体指针。
  3. msgsz:结构体中字符数组的大小。(使用sizeof计算)
  4. msgtyp:消息类型。
  5. 可以为0,也可以为IPC_NOWAIT。

返回值:成功返回消息的数据长度,失败返回-1。

5.控制消息队列

函数原型:

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

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

函数作用:控制消息队列(实现消息队列的删除和修改)。

参数说明:

  1. msgid:消息队列ID。
  2. cmd:控制选项(或控制命令),下面详解
  3. buf:存放属性信息(控制删除是,设置为NULL即可)

返回值:成功返回0,失败返回0。

cmd选项:

  1. IPC_STAT:将msqid消息队列的属性信息,读到第三个参数所指定的缓存。
  2. IPC_SET:使用第三个参数中的新设置去修改消息队列的属性。
  3. IPC_RMID:删除消息队列,用不到第三个参数,用不到时设置为NULL。

6.消息队列的消息结构体

原型如下:

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

成员说明:
mtype:消息类型。
mtext:消息内容。

三、代码演示

  • 进程1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

typedef struct msg
{
    
    
        long mtype;
        char mtext[64];
}MSG,*PMSG;

int main(void)
{
    
    
        key_t key;
        int msgid;
        MSG sendBuf={
    
    888,"Good morning.Have you had your meal."};
        MSG receiveBuf;
        memset(receiveBuf.mtext,'\0',64);

        key = ftok(".",'z');
        if(key == -1)
        {
    
    
                perror("ftok failed:");
                exit(-1);
        }

        msgid = msgget(key,IPC_CREAT|0777);
        if(msgid == -1)
        {
    
    
                perror("msgget failed:");
                exit(-1);
        }

        msgsnd(msgid,&sendBuf,strlen(sendBuf.mtext),0);
        printf("send over\n");

        msgrcv(msgid,&receiveBuf,sizeof(receiveBuf.mtext),999,0);   //读取消息时,要注意大小需要用sizeof来计算
        printf("mtype:%ld,from msg context:%s\n",receiveBuf.mtype,receiveBuf.mtext);

        msgctl(msgid,IPC_RMID,NULL);

        return 0;
}
  • 进程2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

typedef struct msg
{
    
    
        long mtype;
        char mtext[64];
}MSG,*PMSG;

int main(void)
{
    
    
        key_t key;
        int msgid;
        MSG sendBuf={
    
    999,"I have already eaten.What about you"};
        MSG receiveBuf;
        memset(receiveBuf.mtext,'\0',64);

        key = ftok(".",'z');
        if(key == -1)
        {
    
    
                perror("ftok failed:");
                exit(-1);
        }

        msgid = msgget(key,IPC_CREAT|0777);
        if(msgid == -1)
        {
    
    
                perror("msgget failed:");
                exit(-1);
        }


        msgsnd(msgid,&sendBuf,strlen(sendBuf.mtext),0);
        printf("send over\n");

        msgrcv(msgid,&receiveBuf,sizeof(receiveBuf.mtext),888,0);  //读取消息时,要注意大小需要用sizeof来计算
        printf("mtype:%ld,from msg context:%s\n",receiveBuf.mtype,receiveBuf.mtext);

        msgctl(msgid,IPC_RMID,NULL);

        return 0;
}

运行结果如下:

send over
mtype:888,from msg context:Good morning.Have you had your meal.

send over
mtype:999,from msg context:I have already eaten.What about you

总结

参考博文:
https://blog.csdn.net/zhaohong_bo/article/details/89552188
参考书籍:
《UNIX环境高级编程》第三版

Guess you like

Origin blog.csdn.net/weixin_51363326/article/details/116890729