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

消息队列:看到队列,我们可以想到数据结构中所学到的消息队列,它是由一段连续的空间或者以空间块的形式连接在一起的空间。我们可以想到队列中肯定会有 头指针和尾指针,该指针指向的空间肯定存放着我们想要的数据。那么我们进程间通信的消息队列是如何实现的?我们下面来看。

消息队列的定义:
1.消息队列提供了一个进程向另一个进程发送数据块的方法
2.接受的数据块被认为是一个有类型的,所以接受者可以接受不同类型的数据块
3.对比管道,消息队列的消息最大长度也是有一定上限的(MSGMAX),每个消息队列的字节数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI)

我们来看一下消息队列的结构:

struct msqid_ds {
        struct ipc_perm msg_perm;       /* 共有的IPC结构体 */
        struct msg *msg_first;          /* 消息队列头指针 */
        struct msg *msg_last;           /* 消息队列尾指针 */
        __kernel_time_t msg_stime;      /* last msgsnd time */
        __kernel_time_t msg_rtime;      /* last msgrcv time */
        __kernel_time_t msg_ctime;      /* last change time */
        unsigned long  msg_lcbytes;     /* Reuse junk fields for 32 bit */
        unsigned long  msg_lqbytes;     /* ditto */
        unsigned short msg_cbytes;      /* current number of bytes on queue */
        unsigned short msg_qnum;        /* 消息的总数 */
        unsigned short msg_qbytes;      /* 消息队列的最大长度 */
        __kernel_ipc_pid_t msg_lspid;   /* 最后一次发送进程的PID */
        __kernel_ipc_pid_t msg_lrpid;   /* 最后一次发送消息的PID */
};

我们可以看到消息队列在系统中的结构,有一个共享的结构体 struct ipc_perm ;这个结构体中是怎么样的结构呢?

struct ipc_perm
{
        __kernel_key_t  key;          //每个消息队列唯一的标识 key
        __kernel_uid_t  uid;
        __kernel_gid_t  gid;
        __kernel_uid_t  cuid;
        __kernel_gid_t  cgid;
        __kernel_mode_t mode;
        unsigned short  seq;
};

我们了解了消息队列的结构,下面我们看看具体的应用:

发送数据:
int msgsnd(int id,     //msgget返回的id
            const void* msgp,  //数据的起始地址
            size_t msgsz,   //有效数据数据大小,不包括通道号
            int msgflg);   // 0

取出数据:
ssize_t msgrcv(int msqid,// id
             void *msgp,//收到数据放这里
             size_t msgsz,//装数据的地方大小,不包括通道号
             long msgtyp,//从哪个通道读数据
             int msgflg);// 0  IPC_NOWAIT


删除消息队列:
int msgctl(int msqid,//id 
            int cmd,//IPC_RMID
             0);//删除消息队列不关注这个参数

comm.h

#ifndef _COMM_H
#define _COMM_H

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

#define PATHNAME "."
#define PROJ_ID 0x6666

#define SERVER_TYPE 1
#define CLIENT_TYPE 2

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

int createMsgQueue();
int getMsgQueue();
int destroyMsgQueue(int msgid);
int sendMsg(int msgid,int who,char *msg);
int recvMsg(int msgid,int recvType,char out[]);


#endif
~       

comm.c

#include"comm.h"

//创建消息队列 msgget
static int commMsgQueue(int flag)
{
    key_t key = ftok(PATHNAME,PROJ_ID);
    if(key < 0)
    {
        perror("ftok\n");
        return -1;
    }

    int msgid = msgget(key,flag);
    if(msgid < 0)
    {
        perror("msgget\n");
        return -1;
    }

    return msgid;
}

//创建消息队列
int createMsgQueue()
{
    return commMsgQueue(IPC_CREAT|IPC_EXCL|0666);
}
//获取消息队列
int getMsgQueue()
{
    return commMsgQueue(IPC_CREAT);
}
//销毁消息队列
int destroyMsgQueue(int msgid)
{
    if(msgctl(msgid,IPC_RMID,NULL)<0)
    {
        perror("msgctl\n");
        return -1;
    }
    return 0;
}

server.c

#include "comm.h"
#include<stdio.h>
#include<fcntl.h>

int main()
{
    int msgid = createMsgQueue();

    char buf[1024];
    while(1)
    {
        buf[0] = 0;

        recvMsg(msgid,CLIENT_TYPE,buf);
        printf("client # %s\n",buf);

        printf("please enter# ");
        fflush(stdout);
        ssize_t s = read(0,buf,sizeof(buf));

        if(s < 0)
        {
            buf[s-1] = 0;
            sendMsg(msgid,SERVER_TYPE,buf);
            printf("send done, wait recv...\n");
        }
    }

    destroyMsgQueue(msgid);
}

client.c


#include "comm.h"

int main()
{
    int msgid = getMsgQueue();

    char buf[1024];
    while(1)
    {
        buf[0] = 0;
        printf("please enter#");
        fflush(stdout);

        ssize_t s = read(0,buf,sizeof(buf));

        if(s < 0)
        {
            printf("cleint\n");
            buf[s - 1] = 0;
            sendMsg(msgid,CLIENT_TYPE,buf);
            printf("send done,wait recv...\n");
        }

        recvMsg(msgid,SERVER_TYPE,buf);
        printf("server # %s\n",buf);
    }
    return 0;
}

消息队列的存在是有限制的,我们该怎么查看消息队列和删除消息队列呢?
ipcs -q 查看系统中消息队列

还有其他选项这里写图片描述

删除消息队列:
ipcrm -q msgid

这里写图片描述

猜你喜欢

转载自blog.csdn.net/shawei_/article/details/81269896