消息队列:
!一种基于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;
}