Linux---消息队列

消息队列:

!一种基于systemV,从一个进程向另一个进程发送有类型数据块,支持双向通信的方法;
!消息队列的生命周期随内核;
!消息队列的实质是存放消息的链表,存放在内核中并由消息队列标识符标识;
!对消息队列有写权限的进程按照一定的规则向消息队列中发送数据,对消息队列有读权限的进程按照一定规则从消息队列中读取数据;
!读取数据时不需要按照消息队列中消息的顺序进行读取,由于每个消息都有特定的类型,在读取的时候按照自定义的特定类型进行读取。

通过消息队列进行通信示意图:
这里写图片描述
消息队列的创建:
int msgget(key_t key,int msgflg)
参数:key:消息队列的表示符;
msgflg:权限标志。

key值可以用ftok()函数进行实现
系统通过文件信息和proj——id自动合成key值。
key_t ftok(const char*pathname,int proj_id)
参数:pathname为指定的文件名,但必须是存在可以访问的;
proj_id为子序列号,是一个8bit的整数。
返回值:成功返回key,失败返回-1

创建完消息队列之后可以用命令ipcs -q 进行查看消息队列的信息:
这里写图片描述
消息队列的控制:
int msgctl(int msgid,int cmd,struct msqid_ds* buf)
参数:msgid:消息队列的标识;
cmd:对消息队列将要进行的控制行为,分为三个可能取值

IPC_STAT :把msqid_ds结构中的数据设置为消息队列的当前关联值,
IPC_SET:在进程有足够权限的前提下,把消息队列的当前关联值设置为msqid_ds数据结构中给出的值,
IPC_RMID:删除消息队列。

删除消息队列还可以用命令:ipcrm -q msgid

buf:指向msgid_ds结构的指针,指针指向消息队列模式和访问权限的结构。
返回值:成功返回0,失败返回-1.

向消息队列中发送数据:
int msgsnd(int msgid,const void* msgp,size_t msgsz,int msgflg)
参数:msgid:消息队列标识;
msgp:指向要发送消息的指针;
msgsz:发送消息的大小;
msgflg:控制着当消息队列满,或达系统上限时所做的操作。

消息结构体:
strcut msgbuf{
long mtype;//发送数据的类型
char mtext[1];//发送的数据
}

注:消息的类型须是long int,消息的大小须小于系统上限值。

返回值:成功返回0,失败返回-1.

从消息队列接收数据:
size_t msgrcv(int msgid,void* msgp,size_t msgsz,long msgtype,int msgflg)
参数:msgid:消息队列标识;
msgp:指向准备接收的消息的指针;
msgsz:指向msgp消息数据的长度,不包括数据类型;
msgtype:接收数据的类型,实现接收优先级;
msgflg:控制着当消息队列中没有特定类型的消息时做出的动作。
返回值:成功返回实际放在缓冲区中的字符个数,失败返回-1.

消息队列测试:

//Makefile
.PHONY:all
all:server client

server:server.c comm.c
client:client.c comm.c

.PHONY:clean
clean:
        rm -f server client
//comm.h
#ifndef _COMM_H_
#define _COMM_H_

#include<stdio.h>
#include<sys/types.h>
#include<sys/msg.h>
#include<stdlib.h>
#include<string.h>
#define PATHNAME "."
#define PROJ_ID 0x666

#define SERVER 1
#define CLIENT 2

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

int creatMsg();
int getMsg();
int sendMsg(int msgid,int type,const char* msg);
int recvMsg(int msgid,int size,char* out);
int destoryMsg(int msgid);

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

static int Msg(int flags)
{
        key_t key=ftok(PATHNAME,PROJ_ID);
        if(key<0){
                perror("ftok");
                exit(1);
        }

        int msgid=msgget(key,flags);
        if(msgid<0){
                perror("msgget");
                exit(1);
        }
        return msgid;

}

int creatMsg()
{
        return Msg(IPC_CREAT|IPC_EXCL|0666);
}
int getMsg()
{
        return Msg(IPC_CREAT);
}

 int sendMsg(int msgid,int type,const char* msg)
{
        struct msgbuf _mb;
        _mb.mtype=type;
        strcpy(_mb.mtext,msg);
        if(msgsnd(msgid,&_mb,sizeof(_mb.mtext),0)<0){
                perror("msgsnd");
                exit(1);
        }
         return 0;
}

int recvMsg(int msgid,int type,char* out)
{
        struct msgbuf _mb;
        if(msgrcv(msgid,&_mb,sizeof(_mb.mtext),type,0)<0){
                perror("msgrcv");
                exit(1);
     }
        strcpy(out,_mb.mtext);
        return 0;
}

int destoryMsg(int msgid)
{
        if(msgctl(msgid,IPC_RMID,NULL)<0){
                perror("msgctl");
                exit(1);
        }
        return 0;
}             
//server.c
#include"comm.h"

int main()
{
        int msgid=creatMsg();
        char buf[1024];
        while(1){
                recvMsg(msgid,CLIENT,buf);
                printf("client:%s\n",buf);

                printf("Please  enter:\n");
                fflush(stdout);
                size_t size=read(0,buf,sizeof(buf)-1);
                if(size>0){
                        buf[size-1]=0;
                        sendMsg(msgid,SERVER,buf);
                }
                sleep(1);
        }
        destoryMsg(msgid);
}
//client.c
#include"comm.h"

int main()
{
        int msgid=getMsg();
        char msg[1024];
        while(1){
                printf("Please enter:\n");
                fflush(stdout);
                size_t size=read(0,msg,sizeof(msg)-1);
                if(size>0){
                        msg[size-1]=0;
                        sendMsg(msgid,CLIENT,msg);
                }
        recvMsg(msgid,SERVER,msg);
        printf("server:%s\n",msg);
        }
        return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值