消息队列提供了一个进程向另一个进程发送数据块的方法,每个数据块都被认为是有一个类型的,这个类型下文中是用常量is_client_snd和is_server_snd来表示的


消息队列相比管道来说的优点是避免了阻塞。


系统调用函数:

  1. #include<sys/types.h>

    #include<sys/ipc.h>

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

   参数:pathname为一个已存在的、可获得信息的文件的全路径(必须是已经存在的文件)

       proj_id为任意低8位不为0的数(因为要取它的低8位)

    ftok算法

   返回值:成功返回一个key值     失败返回-1

2.#include<sys/types.h>

 #include<sys/ipc.h>

 #include<sys/msg.h>

   原型:int msgget(key_t key,int msgflg);

   参数:key可由ftok获得  

       flag可取三个值 IPC_CREAT  IPC_EXCL   IPC_CREAT|IPC_EXCL 

        IPC_CREAT 创建一个消息队列并返回队列的标识,如果该队列已存在则直接返回该标识 

        IPC_EXCL  本身并没多大意思,通常和IPC_CREAT一起使用

        IPC_CREAT|IPC_EXCL 创建消息队列,如果该队列已经存在则直接返回-1报错,保证资源是              新建的而不是打开的

   返回值:成功返回队列标识 _msg_id   失败返回-1

3.#include<sys/types.h>

 #include<sys/ipc.h>

 #include<sys/msg.h>

接收消息:ssize_t msgrcv(int msgid, const void *msgp,size_t msgsz,int msgtyp,int msgflg);

发送消息:int msgsnd(int msgid,const void *msgp,size_t msgsz,int msgflg));

参 数:   msg_id为消息队列的标识, msgp为指向消息缓冲区的指针(用户可自己制定的通用结构)

       msgsz为消息的大小,msftyp为从队列中取消息的类型,为0可以取任何消息,

       msgflg指明当消息队列中没消息时应该做的指示,0为阻塞,IPC_NOWAIT则直接返回-1;


用到的命令:

  ipcs -q        //查看系统中存在的消息队列

  ipcrm -q key值   //删除指定的key值的消息队列

//comm.h
#ifndef _MSG_QUEUE_
#define _MSG_QUEUE_

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

#define _PATH_ "/tmp/.msg"
#define _PROJ_ID_ 0x55

#define _MSG_SIZE_ 1024

extern const long is_server_snd;
extern const long is_client_snd;

typedef struct _msg_info _msg_info;
struct _msg_info
{
    int mtype;
    char mtext[_MSG_SIZE_];
};

static int comm_msg(int flag);
int creat_msg_queue();
int get_msg_queue();
int destroy(int msg_id);

#endif
//comm.c
#include"comm.h"

const long is_server_snd=1;
const long is_client_snd=2;

static int comm_msg(int flag)
{
    key_t _key=ftok(_PATH_,_PROJ_ID_);
    if(_key<0){
        perror("ftok");
        return -1; 
    }   
    int msg_id= msgget(_key,flag);
    if(msg_id<0){
        perror("msgget");
        return -1; 
    }   
    else
        return msg_id;
}

int creat_msg_queue()
{
    return comm_msg(IPC_CREAT|IPC_EXCL);
}

int get_msg_queue()
{
    return comm_msg(IPC_CREAT);
}

int destroy(int msg_id)
{
    return msgctl(msg_id,IPC_RMID,NULL);
}
//server.c
#include"comm.h"

int main()
{
    int _msg_id=creat_msg_queue();
    _msg_info msginfo;
    while(1){
        msginfo.mtype=is_client_snd;
        memset(msginfo.mtext,'\0',sizeof(msginfo.mtext));
        if(msgrcv(_msg_id,&msginfo,sizeof(msginfo.mtext),is_client_snd,0)<0){
            perror("msgrcv");
        }
        else{
            printf("client say# %s",msginfo.mtext);
        }
        msginfo.mtype=is_server_snd;
        memset(msginfo.mtext,'\0',sizeof(msginfo.mtext));
        read(0,msginfo.mtext,sizeof(msginfo.mtext));
        if(msgsnd(_msg_id,&msginfo,sizeof(msginfo),0)<0){
            perror("msgsnd");
        }
    }
    if(destory(_msg_id)!=0){
        perror("destory failed!\n");
    }
    else
        printf("destory success!\n");

    return 0;
}

//client.c
#include"comm.h"

int main()
{
    int _msg_id= get_msg_queue();
    _msg_info msginfo;
    while(1){
        memset(msginfo.mtext,'\0',sizeof(msginfo.mtext));
        msginfo.mtype=is_client_snd;
        if(read(0,msginfo.mtext,sizeof(msginfo.mtext))>=0){
            if(msgsnd(_msg_id,&msginfo,sizeof(msginfo.mtext),0)<0){
                perror("msgsnd");
            }
        }
        memset(msginfo.mtext,'\0',sizeof(msginfo.mtext));
        if(msgrcv(_msg_id,&msginfo,sizeof(msginfo),is_server_snd,0)<0){
            perror("msgrcv");
        }
        else{
            printf("server say# %s",msginfo.mtext);
        }
    }   
    return 0;
 }
    
  
//Makefile
.PHONY:all
all:server client
server:server.c comm.c
    gcc -o server server.c comm.c
client:client.c comm.c
    gcc -o client client.c comm.c

.PHONY:clean
clean:
    rm -rf server client