消息队列
(一)概念
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。
每一个数据块都被认为是一个有类型,接受者进程接受的数据块可以有不同的类型值。我们可以通过发送消息来避免命名管道的同步与阻塞问题。
消息
队列与管道不同的是,消息队列是基于消息的,而管道是基于字节流的,且消息队列的读取不一定按照先入先出。消息队列与命名管道有一样的不足,就是每个消息的最大长度是有上限的,每个消息队列的总的字节数是有上限的
发送的数据块实际上就是一个结构体,其元素有两个:
①:发送的数据类型,一般由发送方传入
②:数据内容写在mtext[ sz ]中,大小由用户定义
struct msgbuf
{
long mtype;
char mtext[sz];
};
(二)调用函数说明
创建消息队列:
int msgget(key_t key, int msgflg
参数说明:
①
key 可以认为是一个端口号,也可以用ftok 生成
② msgflg :
IPC_CREAT 若消息队列不存在则创建之,否则则打开之
IPC_EXCL单独使用无实际意义,一般与 IPC_CREAT一起使用
IPC_CREAT | IPC_EXCL 若消息队列存在则出错,否则创建之,报名每一次都是一个新的消息队列
返回值说明:
成功执行时,返回消息队列标识值。失败返回-1,errno被设为以下的某个值 ,有时也会返回0,这个时候也
是可以正常使用的EACCES:指定的消息队列已存在,但调用进程没有权限访问它,而且不拥有CAP_IPC_OWNER
权能EEXIST:key指定的消息队列已存在,而msgflg中同时指定IPC_CREAT和IPC_EXCL标志ENOENT:key指定的
消息队列不存在同时msgflg中不指定IPC_CREAT标志 ENOMEM:需要建立消息队列,但内存不足 ENOSPC:需要
建立消息队列,但已达到系统的最大消息队列容量
向队列读/写消息
读取消息:
ssize_t msgrcv(int msqid ,void* msgp, size_t msgsz, long msgtyp, int msgflg)
函数参数说明:
①: msqid 消息队列的标识码
②:创建的struct msgbuf(详见概念)的一个实例的地址,即 将发送的数据块接受并保存在msgp的数据块中
③:传输数据的类型 即 mtext[sz] 的大小
④:struct msgbuf 中 mtype , 即发送者发送的数据类型;如果设置为0,则表示消息队列中的所有消息都会被读取
⑤:一般设置为0,表示阻塞等待的处理模式
函数返回值:
成功返回 0, 否则返回-1
写入消息:
int msgsnd(int msqid, const void* msgp, size_t msgsz, int msgflg)
参数说明:
①:msqid 消息队列的标识码
②:创建的struct msgbuf(详见概念)的一个实例的地址,即 作为发送的数据块
③:发送的数据块中数据的大小,即 struct msgbuf 中 mtext[sz]的大小
④:一般设置为0,表示阻塞等待的处理模式
函数返回值:
成功返回 0, 否则返回-1
设置消息队列属性(其中包括删除):
int msgctl(int msqid, int cmd, struct msqid_ds* buf)
参数说明:
①:msqid 消息队列的标识码
②:cmd分为三种操作:
IPC_STAT:该命令是用来获取消息队列对应的msqid_ds数据结构,并将其保存到buf指
定的·地址空间
IPC_SET:该命令用来设置消息队列的属性,要设置的属性存储在buf中
IPC_RMID:从内核中删除msqid标识的消息队列
(三)代码演示
Comm.h
#ifndef _COMM_H_
#define _COMM_H_
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define PATHNAME "."
#define PROJ_ID 0x6666
#define SIZE 128
#define SERVER_TYPE 1
#define CILENT_TYPE 2
struct msgbuf
{
long mtype;
char mtext[SIZE];
};
int commMsgQueue();
int createMsgQueue();
int getMsg();
int sendMsg(int msqid, long type, const char* buf );
int recvMsg(int msqid, long type, char out[]);
int distroyMsgQueue(int);
#endif
Comm.c
#include "comm.h"
int commMsgQueue(int msgflag)
{
key_t _k = ftok(PATHNAME, PROJ_ID);
if(_k < 0){
perror("ftok");
return -1;
}
printf("%d\n",_k);
int ret = msgget(_k, msgflag);
if(ret < 0){
perror("msgget");
return -2;
}
return ret;
}
int createMsgQueue()
{
return commMsgQueue(IPC_CREAT|IPC_EXCL|0666);
}
int getMsg()
{
return commMsgQueue(IPC_CREAT);
}
int sendMsg(int msqid, long type, const char* buf )
{
struct msgbuf msg;
msg.mtype = type;
strcpy(msg.mtext, buf);
if(msgsnd(msqid, &msg, sizeof(msg.mtext), 0)\
< 0){
perror("msgsnd");
return -1;
}
return 0;
}
int recvMsg(int msqid, long type, char out[])
{
struct msgbuf msg;
if(msgrcv(msqid, &msg, sizeof(msg.mtext), type, 0) < 0){
perror("msgrcv");
return -1;
}
strcpy(out,msg.mtext);
return 0;
}
int distroyMsgQueue(int msgid)
{
if(msgctl(msgid, IPC_RMID, NULL)< 0 ){
perror("msgcrl");
return -1;
}
return 0;
}
cilent.c
#include "comm.h"
int main()
{
int ret = getMsg();
char buf[SIZE];
long type;
while(1)
{
type = SERVER_TYPE;
recvMsg(ret, SERVER_TYPE, buf);
printf("%s\n",buf);
printf("Please Enter#");
fflush(stdout);
ssize_t _s = read(0, buf, sizeof(buf)-1);
if(_s > 0){
type = CILENT_TYPE;
buf[_s-1] = '\0';
sendMsg(ret, type, buf);
}
}
return 0;
}
server.c
#include "comm.h"
int main()
{
int ret = createMsgQueue();
char buf[SIZE];
long type;
while(1)
{
printf("Please Enter#");
fflush(stdout);
ssize_t _s = read(0, buf, sizeof(buf)-1);
if(_s > 0){
type = SERVER_TYPE;
buf[_s-1] = '\0';
sendMsg(ret, type, buf);
}
type = CILENT_TYPE;
recvMsg(ret, type, buf);
printf("%s\n",buf);
}
distroyMsgQueue(ret);
return 0;
}
结果演示: