Linux消息队列实现进程间通信

什么是消息队列:
消息队列提供了从一个进程向另一个进程发送一个有类型数据块的方法。用这种方法可以避免命名管道的同步和阻塞问题。消息队列是基于消息的,而管道是基于字节流的,并且消息队列的读取不一定是先入先出。

消息队列的操作:
消息队列的创建或者获取:
int msgget(key_t key, int msgflg);
参数描述:
key:是一个端口号,可以由ftok()生成
msgflg:  IPC_CREAT:如果IPC不存在,则创建,存在就打开
                IPC_EXECL:单独使用无太大意义,与IPC_CREAT一块使用代表,IPC不存在创建,存在出错,返回
key_t ftok(const char *pathname, int proj_id);
生成唯一一个key供用户使用,返回一个消息队列标识符。
返回值:
成功返回消息队列的id,失败返回-1。
读取消息:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数描述:
msgid:消息队列的标识符
msgp:指向一个缓冲区的指针,用来暂时存放储存发送和接受的消息,是一个用户可以定义的通用结构。
struct msgstru{
    long mtype; //大于0
    char mtext;//用户指定大小
};
msgz:消息的大小
msgtyp:从消息队列中读取的消息形态
msgflg:用来指明核心程序在队列没有数据的情况下所应采取的行动。如果msgflg和常 数IPC_NOWAIT合用,则在msgsnd()执行时若是消息队列已满,则msgsnd()将不会阻塞,而 会立即返回-1,如果执⾏行的是msgrcv(),则在消息队列呈空时,不做等待马上返回-1,并设定 错误码为ENOMSG。当msgflg为0时,msgsnd()及msgrcv()在队列呈满或呈空的情形时,采取 阻塞等待的处理模式。
返回值:
成功返回实际读取到的字节数,失败返回-1。
发送消息:
int msgsnd(int msqid, const void *msgp, size_t msgz, int msgflg);
参数与读取消息函数的参数相同。
返回值;
成功返回0,失败返回-1。

消息队列的查看:
可以使用 ipcs -q 来查看系统中的消息队列;
可以使用ipcrm -q +消息队列id  来删除对应id的消息队列

消息队列的实例:
实现一个server和一个client程序,他们之间利用消息队列进行通信。
comm.h
#ifndef  _COMM_H_
#define  _COMM_H_
#ifndef  _COMM_H_
#define  _COMM_H_

#include
#include
#include
#include
#include

#define PATHNAME "."
#define PROJ_ID 0x666

#define SERVER_TYPE 1
#define CLIENT_TYPE 2

//自定义一个缓冲区用来暂时存储发送或者接收的数据
struct msgbuf
{
    long mytype;
    char mtext[1024];
};
int createMsgQueue();
int getMsgQueue();
int destroyMsgQueue(int msgid);
int sendMsg(int msgid, int type, char *msg);
int recvMsg(int msgid, int recvType, char out[]);
#endif

comm.c
#include "comm.h"

//创建或者打开消息队列
static int commMsgQueue(int flag)
{
    key_t key = ftok(PATHNAME, PROJ_ID);
    if(key < 0)
    {
    perror("ftok");
    return -1;
    }
    //根据flag的不同选择打开还是创建
    int msgid = msgget(key, flag);
    if(msgid < 0)
    {
    perror("msgget");
    return -2;
    }
    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");
    return -1;
    }
    return 0;
}
//发送消息(参数:发送者,发送内容的类型,发送的内容)
int sendMsg(int msgid, int who, char *msg)
{
    //buf 自定义的缓冲区,用来暂存数据
    struct msgbuf buf;
    buf.mytype = who;
    strcpy(buf.mtext, msg);
    //进行发送,将缓冲区中的数据进行发送
    if(msgsnd(msgid, (void *)&buf, sizeof(buf.mtext), 0) < 0)
    {
    perror("msgsnd");
    return -1;
    }
    return 0;
}
//接收消息(参数:接受者,接受类型,接受之后存放位置)
int recvMsg(int msgid, int who, char out[])
{
    struct msgbuf buf;
    buf.mytype = who;
    //接收数据,将接收的数据写入到缓冲区中
    if(msgrcv(msgid, (void *)&buf, sizeof(buf.mtext), recvType, 0)< 0)
    {
    perror("msgrcv");
    return -1;
    }
    //将数据从缓冲区存放到指定位置
    strcpy(out, buf.mtext);
    return 0;
}

server.c
#include"comm.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...\n");
    }
    }
    //服务器端创建,服务器端销毁消息队列
    destoryMsgQueue(msgid);
    return 0;
}

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)
    {
        buf[s-1] = 0;
        //将缓冲发送到服务器
        sendMsg(msgid, CLIENT_TYPE, buf);
        printf("send done...\n");
    }
    //接受服务器的回应
    recvMsg(msgid, SERVER_TYPE, buf);
    printf("Server : %s\n", buf);

    }
   return 0;
}

运行结果:


你可能感兴趣的:(Linux)