进程间通信——消息队列


前言


进程间需要进程通信进行数据传输和资源共享,另外一个进程在很多时候需要向另外的一个进程通知事件,有时候进程之间存在关系,需要去控制另外的一个进程,所以进程通信是很需要的。

进程间通信的第一种就是消息队列

什么是消息队列


消息队列是消息的链表,存放在内核当中,由消息队列标识符标识,消息队列提供一种进程之间数据块传送的方法,每个数据块都被认为是一种类型。每个进程都有一个与之相关联的消息队列,其功能就类似于一个信箱

注意


因为管道是随进程的,进程结束管道生命周期也就结束,而对于消息队列来说,是随操作系统的,就算进程突出,不去手动的释放消息队列,消息队列依然是存在的。
我们可以使用ipcs -q进行查看操作系统的消息队列,使用ipcrm -q msgid进行销毁消息队列。

消息队列的创建


使用msgget函数,我们可以创建或者访问一个消息队列,
在创建消息队列之前我们依然要用ftok得到一个key标识符。

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

这里的pathname是路径,proj_id用来指定数字,为生成唯一的key提供。该函数把从pathname导出的信息与id的低序8位组合成⼀个整数IPC键。

然后创建队列。

int msgget(key_t key, int msgflg);

msgflg使用IPC_CREATE和IPC_EXCL进行创建消息队列,当msgflg使用IPC_CREATE和0的时候,这个时候使用消息队列。

函数返回值返回一个msgid,失败返回-1。

发送消息和接受消息


使用消息队列当然涉及到发送消息和接受消息,msgsnd函数和msgrcv函数提供了这两个功能,

首先来看msgsnd函数

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

在这里我们需要关注第二个参数,第二个参数是指向一个结构体的一个指针,这个结构体叫做 struct msgbuf

 struct msgbuf {
               long mtype;       /* message type, must be > 0 */
               char mtext[用户指定大小];    /* message data */
           };

这个结构体第一个变量是消息的类型,第二个是存放消息的数组。
这个结构体早sys/msg.h当中已经有定义,所以我们可以直接拿来用就行。

然后看msgsnd的后面两个参数:
msgsz是注意是消息的长度,而不是整个结构体的长度,也就是说msg_sz是不包括长整型消息类型成员变量的长度,是指第二个参数制作指向的消息长度。

msgflg,用来指明在没有数据的情况下所需要做的操作,这个操作我们经常使用IPC_NOWAIT,这样当消息队列满了的时候,再向消息队列中发送消息,不会发生阻塞现象。

当调用成功,这个时候消息数据将被拷贝放入到消息队列中
接收消息:

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

msgrcv函数第二个参数,同样是指向消息队列结构体的指针,第三个参数和第四个也和上述是一样的。

当调用成功的时候,返回消息队列接受缓存当中的字节数,消息复制到用户缓冲区,然后删除消息队列当中的对应的信息。

控制消息队列


控制消息队列需要使用的函数是msgctl函数,

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

这个函数中的cmd参数提供需要的操作,例如使用IPCRMID就可以进行删除消息队列。

示例:


我们使用服务器进程进行创建消息队列,然后使用客户进程进行send数据,服务进程接收数据。

comm.h

#ifndef __COMM_H__
#define __COMM_H__
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/types.h>
#include<string.h>
#include<time.h>

#define _MSG_SIZE_ 1024
#define FILEPATH "."
#define PROJID 0
#define PERM 0666
#define SERVER_TYPE 1
#define CLIENT_TYPE 2
#define MYSIZE 128

struct msgbuf
{
    long mtype;
    char mtext[MYSIZE];
};

static int commmsg(int msgflg);
int createmsg();
int sendmsg(int msgid,long type,const char * msg);
int getmsg();
int recvmsg(int msgid,int type,char out[]);
int destorymsg(int msgid);

#endif //!__COMM_H__

comm.c


#include"comm.h"

static int commmsg(int msgflg)
{
    key_t key=ftok(FILEPATH,PROJID);
    if(key<0)
    {
       perror("ftok");
        return -1;
    }
    int msqid=msgget(key,msgflg);
    if(msqid<0)
    {
        perror("msgget");
        return -2;
    }
    return msqid;
}
int createmsg()
{
    return commmsg(IPC_CREAT|IPC_EXCL|PERM);   
}
int getmsg()
{
    return commmsg(0);
}
int sendmsg(int msgid,long type,const char *msg)
{
    struct msgbuf buf;

    buf.mtype=type;
    strcpy(buf.mtext,msg);

    int id=msgsnd(msgid,&buf,sizeof(buf.mtext),0);
    if(id<0)
    {
        perror("msgsnd");
        return -1;
    }
    return 0;
}
int recvmsg(int msgid,int type,char out[])
{
    struct msgbuf buf;
    int size=msgrcv(msgid,&buf,sizeof(buf.mtext),type,0);
    if(size>0)
    {
        //buf.mtext[size]='\0';
        strncpy(out,buf.mtext,size);
        return 0;

    }
    perror("msgrcv");
    return -1;
}
int destorymsg(int msgid)
{
    if(msgctl(msgid,IPC_RMID,NULL)<0)
    {
        perror("msgctl");
        return -1;
    }
    return 0;
}

client.c

#include"comm.h"
int main()
{
    int msqid=getmsg();
    char buf[MYSIZE];
    char out[2*MYSIZE];
    while(1){
        printf("please input:");
        fflush(stdout);

        ssize_t _s=read(0,buf,sizeof(buf)-1);
        if(_s>0)
        {
            buf[_s]='\0';
            sendmsg(msqid,CLIENT_TYPE,buf);
        }
        if(recvmsg(msqid,SERVER_TYPE,out)<0)
        {
            break;
        }
        printf("server echo :%s\n",out);
    }

    return 0;

}

server.c

#include"comm.h"
int main()
{
    int msqid=createmsg();
    char buf[2*MYSIZE];
    while(1){
        if(recvmsg(msqid,CLIENT_TYPE,buf)<0)
        {
            break;
        }
        printf("client# %s\n",buf);
        if(sendmsg(msqid,SERVER_TYPE,buf)<0)
        {
            break;   
        }
    }
    destorymsg(msqid);

    return 0;
}

这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值