消息队列

  • sys/msg.h
#include <sys/msg.h>


int main(void){
    // 创建消息队列
    // 通过key创建或获取消息队列 返回消息队列ID 失败返回-1
    /*
     * msgget 创建或获取消息队列
     *  key: ftok函数返回的key
     *  msgflg 标志位置
     *      0           - 获取 不存在即失败(是否存在根据key来判断)
     *      IPC_CERAT   - 创建 不存在即创建,已存在即获取(是否存在根据key来判断)
     *      IPC_EXCL    - 排它 不存在即创建,已存在即失败(是否存在根据key来判断)
     * */
    // 表示创建权限为0664内存不获取旧的消息队列


    // 发送消息
    /*
     * msgsnd 发送消息
     * msgid int msgget获取的消息队列ID
     * msgp void const*  指针,指向一块包含消息类型和消息数据的内存块,该内存的前4(如果是64为系统则是前8)个字节必须是一个大于0的整数,代表消息类型,其后紧跟消息数据v
     * msgsz size_t 期望发送消息数据(不包含消息类型)的字节数
     * msgflg int  发送标志(阻塞、非阻塞),一般取0
     *      0 阻塞
     *      IPC_NOWAIT 非阻塞 当内核消息队列已达上线 会返回-1 并且errno 设置为EAGAIN
     * */

    // 接收消息
    /*
     * msgrcv 接收消息
     * msgid int msgget获取的消息队列ID
     * msgp void const*  指针,指向一块包含消息类型和消息数据的内存块,该内存的前4(如果是64为系统则是前8)个字节必须是一个大于0的整数,代表消息类型,其后紧跟消息数据v
     * msgsz size_t 期望接收消息数据(不包含消息类型)的字节数
     * msgtype long 消息数据的类型
     *      0 默认。接收消息队列的第一条数据
     *      >0 如果msgflg参数不包含MSG_EXCEPT位,则提取消息队列第一条类型为msgtype的消息,如果msgflg参数包含MSG_EXCEPT位,则提取消息队列第一条类型不为msgtype的消息
     *      <0 提取消息队列中类型小于等于绝对值msgtype的消息,类型越小消息越被优先提取
     * msgflg int  发送标志(阻塞、非阻塞),一般取0
     *      0 阻塞
     *      IPC_NOWAIT 非阻塞 当内核消息队列已达上线 会返回-1 并且errno 设置为EAGAIN
     * 注:
     *  1.如果存在匹配类型的消息数据,但是数据长度大于msgsz,并且msgflg位包含MSG_NOERROR,则之截取msgsz数据剩余的直接丢弃,如果msgflg位不包含MSG_NOERROR,则不处理该消息,返回-1 并且errno 设置为E2BIG
     *  2.如果存在匹配类型的消息数据,msgrcv函数会将消息移出消息队列,并返回所接收到消息数据的字节数,表示接收成功。
     *     否则函数会阻塞,直到消息队列中有可接受的消息为止,如果msgflg位包含IPC_NOWAIT,则函数不会阻塞,而是返回-1,并且errno 设置为ENOMSG
     *
     * */

    // 消息控制
    /*
     * msgctl
     * msgid int msgget获取的消息队列ID
     * cmd   要做的操作
     *      IPC_RMID 销毁共享内存
     *  buf NULL
     *  成功返回0 失败返回-1
     *  备注:调用销毁时,并非立即销毁,需要加载计数为0时才真正销毁;并且其他进程无法创建与这块共享内存的映射,之前已经创建的不受影响
     * */

    return 0;
}
  • 写端
#include <stdio.h>
#include <sys/msg.h>
#include <string.h>

int main(void) {
    // 创建key
    key_t key = ftok(".", 8);
    // 创建消息队列
    int msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0664);
    // 往消息队列中发送消息
    for (;;) {
        struct {
            long msgType;
            char msgData[128];
        } msgBuf = {100, ""};
        fgets(msgBuf.msgData, sizeof(msgBuf.msgData), stdin);
        if (strcmp(msgBuf.msgData, "!\n") == 0) {
            break;
        }
        if (msgsnd(msgid, &msgBuf, sizeof(msgBuf) - sizeof(msgBuf.msgType), 0) == -1) {
            perror("msgsnd");
            return -1;
        }
    }
    // 销毁消息队列
    if (msgctl(msgid, IPC_RMID, NULL) == -1) {
        perror("msgctl");
        return -1;
    }
    return 0;
}
  • 读端
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/msg.h>
#include <string.h>
#include <errno.h>

int main(void) {
    // 创建key
    key_t key = ftok(".", 8);
    // 获取消息队列
    int msgid = msgget(key, 0);
    // 接收消息
    for (;;) {
        struct {
            long msgType;
            char msgData[128];
        } msgBuf = {100, ""};
        if (msgrcv(msgid, &msgBuf, sizeof(msgBuf) - sizeof(msgBuf.msgType), 100, 0) == -1) {
            if (errno == EIDRM) {
                printf("消息队列关闭\n");
                break;
            } else {
                perror("msgrcv");
                return -1;
            }

        }
        printf("msgType:%ld msgData:%s\n", msgBuf.msgType, msgBuf.msgData);
    }

    return 0;
}

posted on 2023-05-03 17:06  信奉上帝的小和尚  阅读(10)  评论(0编辑  收藏  举报

导航