XSI IPC之消息隊(duì)列詳解

命令 ipcs 查看消息隊(duì)列,共享內(nèi)存,信號量數(shù)組的信息

命令 ipcrm -q id 銷毀一個(gè)消息隊(duì)列

消息隊(duì)列

man 7 mq_overview 消息隊(duì)列概述

man msgop 消息隊(duì)列操作函數(shù)

ftok(3)

將路徑名或項(xiàng)目標(biāo)識符轉(zhuǎn)換為系統(tǒng),即轉(zhuǎn)換成 key_t 類型

函數(shù)聲明

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

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

參數(shù)含義

(文件路徑,8位proj_id)

返回值

成功返回 key_t 類型,失敗返回-1并設(shè)置errno

示例

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

#define PATHNAME    "/etc/passwd"
#define PRO_ID      'a'

int main(void)
{
    key_t key;
    key = ftok(PATHNAME, PRO_ID);
    if (-1 == key) 
    {
        perror("ftok()");
        exit(1);
    }
    exit(0);
}

msgget(2)

創(chuàng)建消息隊(duì)列實(shí)例

函數(shù)聲明

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

int msgget(key_t key, int msgflg);

參數(shù)含義

(ftok返回的key_t類型,與key參數(shù)值相關(guān)的標(biāo)識符)

如果 key值為 IPC_PRIVATE 則只能用于有親緣關(guān)系

標(biāo)識符可選(多選用或運(yùn)算)

IPC_CREAT 創(chuàng)建,需要或上文件權(quán)限

IPC_EXCLIPC_CREAT一起使用,確保如果消息隊(duì)列已經(jīng)創(chuàng)建,返回失敗

返回值

成功返回 int 類型消息隊(duì)列號

失敗返回 -1 并且設(shè)置errno 如果標(biāo)識符使用了IPC_CREATIPC_EXCL 并且errno的值為EEXIST,代表消息隊(duì)列已經(jīng)存在。

msgsnd(2) /msgrcv(2)

向管道發(fā)送消息,接收消息

函數(shù)聲明

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

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

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

參數(shù)含義

msqid為msgget(2)函數(shù)的返回值

msgp是一個(gè)結(jié)構(gòu)體首地址,該結(jié)構(gòu)體類型為

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

msgsz為struct msgbuf結(jié)構(gòu)體中mtext大大小

msgflg為可選參數(shù),對數(shù)據(jù)不加要求傳0,可選值詳見man手冊

msgtyp為需要屏蔽的數(shù)據(jù)類型

返回值

失敗都返回-1并設(shè)置<u>errno</u>值

成功msgsnd(2)返回0,msgrcv(2)返回收到的字節(jié)個(gè)數(shù)

msgctl(2);

銷毀隊(duì)列

函數(shù)聲明

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

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

消息隊(duì)列示例

首先需要一個(gè) .h 文件,兩個(gè).c文件,兩個(gè).c文件需要共用一個(gè)key值

proto.h文件

用來聲明兩個(gè).c文件公用的變量

#ifndef __PROTO_H
#define __PROTO_H

#define PATHNAME    "/etc/passwd"
#define PRO_ID      'a' 
#define NAMESIZE    32

struct stu_st {
    int id;
    char name[NAMESIZE];
};

// 交換的數(shù)據(jù)
struct msgbuf {
    long mtype;
    struct stu_st stu;
};

#endif
接收端 rcv.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <errno.h>
#include <stdlib.h>

#include "proto.h"

int main(void)
{
    key_t key;
    int msgid;
    struct msgbuf rcvbuf;
    int cnt;
    int created = 1;

    key = ftok(PATHNAME, PRO_ID);
    if (-1 == key) {
        perror("ftok()");
        exit(1);
    }
    // 獲取/創(chuàng)建實(shí)例
    msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0600);
    if (msgid == -1) {
        if (errno == EEXIST) {
            msgid = msgget(key, 0);
            created = 0;
        } else {
            perror("msgget()");
            exit(1);
        }
    }

    while (1) {
        cnt = msgrcv(msgid, &rcvbuf, sizeof(struct stu_st), 3, 0);  
        if (cnt == -1) {
            if (errno == EINTR)
                continue;
            perror("msgrcv()");
            exit(1);
        }
        printf("rcv type:%ld, data:%d %s\n", rcvbuf.mtype, rcvbuf.stu.id, rcvbuf.stu.name); 
    }

    return 0;
ERROR:
    if (created)
        msgctl(msgid, IPC_RMID, NULL);
    exit(1);
}
發(fā)送端send.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

#include "proto.h"

int main(int argc, char *argv[])
{
    key_t key;
    int msgid;
    struct msgbuf sndbuf;
    int created = 1;

    if (argc < 3)
        exit(1);

    key = ftok(PATHNAME, PRO_ID);
    if (-1 == key) {
        perror("ftok()");
        exit(1);
    }
    // 獲取/創(chuàng)建實(shí)例
    msgid = msgget(key, IPC_CREAT | IPC_EXCL);
    if (msgid == -1) {
        if (errno == EEXIST) {
            msgid = msgget(key, 0);
            created = 0;
        } else {
            perror("msgget()");
            exit(1);
        }
    }

    sndbuf.mtype = atoi(argv[1]);
    sndbuf.stu.id = atoi(argv[2]);
    strcpy(sndbuf.stu.name, argv[3]);

    msgsnd(msgid, &sndbuf, sizeof(struct stu_st), 0);

    if (created)    
        msgctl(msgid, IPC_RMID, NULL);

    return 0;
}
測試函數(shù)main.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/wait.h>
#include <string.h>

#define STRSIZE 100

struct msgbuf {
    long mtype;
    char str[STRSIZE];
};

int main(void)
{
    int msgid;
    pid_t pid;
    struct msgbuf sndbuf, rcvbuf;
    int cnt;

    msgid = msgget(IPC_PRIVATE, IPC_CREAT | 0600);
    if (msgid == -1) {
        perror("msgget()");
        exit(1);
    }
    
    pid = fork();
    // if error

    if (pid == 0) {
        strcpy(sndbuf.str, "good afternoon");
        sndbuf.mtype = 1;
        sleep(2);
        if (msgsnd(msgid, &sndbuf, strlen(sndbuf.str)+1, 0) == -1) {
            perror("msgsnd()");
            exit(1);
        }
        exit(0);
    }

    cnt = msgrcv(msgid, &rcvbuf, STRSIZE, 0, 0);
    if (cnt == -1) {
        perror("msgrcv()");
        exit(1);
    }
    printf("type:%ld, data:%s\n", rcvbuf.mtype, rcvbuf.str);

    wait(NULL);

    msgctl(msgid, IPC_RMID, NULL);

    exit(0);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容