进程间的通信——消息队列

IPC(Inter-Process Communication,进程间通信)消息队列是一种在不同进程之间传递数据的机制。它允许多个进程通过共享的消息队列进行异步通信。

消息队列是在内核中创建和维护的,用于存储和传递消息。多个进程可以通过使用相同的消息队列标识符来访问同一个消息队列。每个消息都有一个类型和数据部分,进程可以按照类型从消息队列中读取特定类型的消息。

使用IPC消息队列进行进程间通信的一般步骤如下:

  1. 创建或获取消息队列:使用msgget函数创建或获取一个消息队列。该函数返回一个唯一的消息队列标识符。

  2. 发送消息到消息队列:使用msgsnd函数向消息队列发送消息。需要指定消息队列标识符、消息数据和消息类型。

  3. 接收消息:使用msgrcv函数从消息队列接收消息。可以根据消息类型选择接收特定类型的消息。

  4. 删除消息队列:当不再需要消息队列时,可以使用msgctl函数删除消息队列。需要提供消息队列标识符和删除命令。

与消息队列相关的常用 API 包括以下几个:

  1. msgget:创建或获取一个消息队列。
int msgget(key_t key, int msgflg);
  • key:表示消息队列的键值,可以通过 ftok 函数生成。它是一个唯一的标识符,用于标识特定的消息队列。多个进程可以通过相同的 key 值来获取同一个消息队列。注意,在不同的进程中使用相同的 key 来获取消息队列时需要保证权限和存在性。
  • msgflg:用于指定操作的行为选项,是一个标志参数。可以通过以下标志进行组合:

    • IPC_CREAT:如果指定的消息队列不存在,则创建一个新的消息队列。如果已存在,则返回该消息队列的标识符。
    • IPC_EXCL:与 IPC_CREAT 一同使用,只有在消息队列不存在的情况下才创建新的消息队列,否则会返回错误。
    • 还可以与文件的读写权限进行按位或运算,例如 IPC_CREAT | 0666 表示创建对所有用户可读可写的消息队列。
  • 返回值为消息队列的标识符,即一个正整数。如果成功创建或获取消息队列,则返回一个非负整数表示消息队列的标识符。如果出现错误,则返回 -1,并相应地设置 errno 变量来指示错误的原因。

补充:

ftok 是一个用于生成唯一标识符(key)的函数,通常用于创建共享内存和消息队列等进程间通信机制。

函数原型:

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

参数解释:

  • pathname:一个存在的文件路径名,用于生成唯一的 key。可以是任意有效的文件路径。
  • proj_id:一个用户定义的整数,用于区分不同的标识符。通常为正整数。

返回值:

  • 如果成功,返回一个唯一的 key 值。
  • 如果出错,返回 -1,并设置 errno 错误码来指示具体错误。

ftok 函数通过将给定的 pathname 转化为一个无符号的整数标识符,并与 proj_id 进行组合,生成一个唯一的 key。这个 key 可以用于创建或获取共享内存或消息队列等进程间通信机制。

需要注意的是,ftok 函数生成的 key 可能在不同系统上有不同的表示方式,因此在跨平台的程序中需要小心使用。另外,ftok 生成的 key 并不是全局唯一的,仅在相同的 pathnameproj_id 下才能保证唯一性。

2.msgsnd:向消息队列发送消息。

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

返回值为操作的结果,即一个非负整数。如果成功发送消息,则返回0。如果出现错误,返回-1,并设置 errno 变量来指示错误的原因。

  • msqid:表示消息队列的标识符,即通过 msgget 函数获取到的值。

  • msgp:指向要发送的消息的指针,通常是一个自定义的结构体指针。

  • msgsz:表示要发送消息的大小,以字节为单位。注意,该大小必须至少大于等于 msgp 指向的消息结构体的大小。

  • msgflg:用于指定发送消息的行为选项,是一个标志参数。

    可以通过以下标志进行组合:

    • 0:阻塞模式,如果发送队列已满,则调用进程被阻塞,直到有空间可以发送消息。
    • IPC_NOWAIT:非阻塞模式,如果发送队列已满,则返回错误而不等待。
    • 其他标志可以与上述标志进行按位或运算,例如 IPC_NOWAIT | <其他标志>

3.msgrcv:从消息队列接收消息。

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
  • msqid:表示消息队列的标识符,即通过 msgget 函数获取到的值。

  • msgp:指向消息缓冲区的指针,用于接收接收到的消息内容。通常是一个自定义的结构体指针。

  • msgsz:表示消息缓冲区的大小,以字节为单位。注意,该大小必须至少大于等于消息结构体的大小,以确保能够容纳接收到的消息内容。

  • msgtyp表示接收消息的类型。可以通过不同的 msgtyp 值来选择接收具有不同类型的消息。常见的取值如下:

    • 0:接收队列中的第一个消息。
    • >0:接收队列中消息类型等于 msgtyp 的第一个消息。
    • <0:接收队列中消息类型小于等于 msgtyp 绝对值的最小消息。 注意,如果指定了非零的 msgtyp 值,则只接收匹配类型的消息;如果指定了 0,则接收队列中的第一个消息。
  • msgflg:用于指定接收消息的行为选项,是一个标志参数。

    可以通过以下标志进行组合:

    • 0:阻塞模式,如果接收队列中没有符合条件的消息,则调用进程被阻塞,直到有可接收的消息。
    • IPC_NOWAIT:非阻塞模式,如果接收队列中没有符合条件的消息,则返回错误而不等待。
    • 其他标志可以与上述标志进行按位或运算,例如 IPC_NOWAIT | <其他标志>

4.msgctl:对消息队列进行控制操作。

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
  • 参数 msqid 是消息队列的标识符。
  • 参数 cmd 是控制命令,用于指定要执行的操作,如删除队列、获取或设置属性等。
  • 参数 buf 是指向 struct msqid_ds 结构体的指针,用于传递或接收消息队列的状态信息。
  • 返回值表示函数执行成功与否。

 下面是通过创建消息队列来实现不同进程的通信:

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

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

int main() {
    // Generate a unique key for the message queue using ftok function
    key_t key;
    key = ftok(".", 2);
    if (key == -1) {
        perror("ftok error");
        exit(1);
    }
    printf("key id = %d\n", key);

    // Create or get the message queue using msgget function
    struct msgbuf recbuf = {.mtext = {0}};
    int qid = msgget(key, IPC_CREAT | 0666);
    if (qid == -1) {
        perror("Error creating or getting message queue:");
        exit(1);
    }

    // Receive a message from the message queue using msgrcv function
    msgrcv(qid, &recbuf, sizeof(recbuf.mtext), 666, 0);
    printf("Received data from queue %d: %s\n", qid, recbuf.mtext);

    // Prepare a message to send back
    struct msgbuf send = {999, "Received, thank you!"};

    // Send a message to the message queue using msgsnd function
    msgsnd(qid, &send, strlen(send.mtext), 0);
    printf("Sent message back to the queue\n");

    // Remove the message queue using msgctl function
    msgctl(qid, IPC_RMID, NULL);

    return 0;
}

 结果:

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MichstaBe#

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值