进程间通信笔记(4)—SystemV 消息队列

1.概述

SystemV 消息队列使用消息队列标识符标识,这个标识好像链表中的头节点,包含了许多信息,当然最主要的还是指向数据节点的两个指针msg_firstmsg_last,分别表示消息队列中的第一个和最后一个消息节点。

这里写图片描述


2.消息队列函数

操作SystemV消息队列的函数。

2.1 msgget函数

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

int msgget(key_t key, int msgflg);

其中key既可以是IPC_PRIVATE,也可以是ftok函数的返回值。当key的值为IPC_PRIVATE或者当前没有消息队列与给定key相关联时,将创建一个新的消息队列。

msgflg指定获取消息队列时的权限组合:当它被指定IPC_CREATIPC_EXCL时且跟key关联的消息队列已经存在,则msgget调用失败且设置errno=EEXIST

2.2 msgsnd函数

msgget打开一个消息队列后,我们使用msgsnd往其放一个消息,好像链表插入新节点。

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

msqid是msgget返回的标识符
msgp是一个结构指针,它有一个模板:

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

不过一般情况下,应用通常使用自己定义的消息类型,消息内容也不仅仅局限于文本,因为对于msgp来说,它只是一个指针而已。

2.3 msgrcv函数

从消息队列中读出一个消息。

#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);

其中msgp参数指定接收消息的存放位置,与msgsnd一样,该指针指向紧挨在真正的消息数据之前返回的长整数类型字段。
msgsz指定了数据大小,不包含类型字段。
msgtyp指定读出消息的类型。
msgflg指定请求类型消息不在队列时怎么处理。
成功返回时,将返回接收消息中数据的字节数,不含消息类型的那几个字节。


3. System V消息队列编程

依然是实现简单生产者消费者模型,不同管道,某个进程往一个队列中写入一个消息之前,不求另一个某个进程正在等待该队列上的一个消息到达。

数据结构定义

//msg.h

#ifndef __MSG_H__
#define __MSG_H__
#define MAXSIZE 256
struct Message_
{
    long mtype;
    unsigned int mlength;
    char buff[MAXSIZE];
};
typedef struct Message_ Message;
#endif

发送方(生产者)

//sysV_send.c

#include <stdio.h>  
#include <sys/ipc.h>  
#include <sys/msg.h>  
#include <errno.h>  
#include <assert.h>  
#include <string.h>
#include "msg.h"

int main(int argc,char **argv)
{
    const char * const pathname="/home/zhangxiao/zxtest/systemV/";//ftok所需的pathname
    int msqid;
    key_t key;
    int mflag;
    Message msg;
    //0600 拥有者拥有读写权限。
    mflag=IPC_EXCL|IPC_CREAT|0600;



    key = ftok(pathname,1);//ftok 获取 key
    if(key<0)
    {
        fprintf(stderr, "ftok: %s\n", strerror(errno));  
        return -1;
    }


    msqid=msgget(key,mflag);//msgget函数调用

    if((msqid < 0) && (errno!=EEXIST))//msgget失败且不是因为消息队列已经存在
    {
        fprintf(stderr, "msgget: %s\n", strerror(errno));  
        return -1;  
    }
    if(msqid < 0)//消息队列已经存在
    {
        printf("debug...\r\n");//说明打开的消息队列已经存在
        msqid=msgget(key,IPC_CREAT|0600);//将忽视IPC_CREAT关键字
        if (msqid < 0) {  
            fprintf(stderr, "msgget: %s\n", strerror(errno));  
            return -1;  
        }
    }

    memset(&msg,0x00,sizeof(Message));
    strcpy(msg.buff,"HelloWorld666");
    msg.mlength=strlen(msg.buff);
    int i;
    for(i = 0;i < 3;i++ )
    {
        msg.mtype=(i+1)*100;
        if(msgsnd(msqid,(void *)&msg,sizeof(Message),0)<0)//发送消息
        {
            fprintf(stderr, "msgsnd: %s\n", strerror(errno));  
            return -1;  
        }
    }
    return 0;
}

接收方(消费者)

#include <stdio.h>  
#include <sys/ipc.h>  
#include <sys/msg.h>  
#include <errno.h>  
#include <assert.h>  
#include <string.h>
#include "msg.h"


int main(int argc,char **argv)
{
    const char * const pathname="/home/zhangxiao/zxtest/systemV/";
    int msqid;
    key_t key;
    key = ftok(pathname,1);//ftok 获取 key
    Message msg;
    ssize_t n;
    if(key<0)
    {
        fprintf(stderr, "ftok: %s\n", strerror(errno));  
        return -1;
    }
    msqid=msgget(key,IPC_CREAT);//将忽视IPC_CREAT关键字
    if (msqid < 0) 
    {  
        fprintf(stderr, "msgget: %s\n", strerror(errno));  
        return -1;  
    }

    memset(&msg,0x00,sizeof(Message));


    int i;
    for(i=2;i>=0;i--)
    {
        n=msgrcv(msqid,&msg,sizeof(Message),(i+1)*100,0);
        printf("msgtype=%ld,message=%s\r\n",msg.mtype,msg.buff);
    }

    msgctl(msqid,IPC_RMID,0);//删除消息队列
    return 0;
}

Makefile

# Makefile

PROGS =Send Recv
CLEANFILES = core core.* *.core *.o temp.* *.out typescript* \
        *.lc *.lh *.bsdi *.sparc *.uw

all :${PROGS}


CFLAGS+=-g   
LIBS+=

Recv: sysV_recv.o
    @${CC} ${CFLAGS} ${LIBPATH} $^  -o $@ ${LIBS}  
    @rm *.o

Send: sysV_send.o
    @${CC} ${CFLAGS} ${LIBPATH} $^ -o $@   ${LIBS}  
    @rm *.o

clean:
    rm -f ${PROGS} ${CLEANFILES}

4.补充

终端可以使用ipcs等命令查看和操作systemV IPC对象。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值