在Linux中,IPC消息队列是一个双向通信的全内存设计,即内核保证了读写顺序和数据同步,并且是性能比较优越的先进先出数据结构。消息队列应用于很多场景:比如异步任务处理,抢占式的数据分发,以及顺序缓存区等。
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。
每个数据块都被认为含有一个类型,接受者接受的数据块可以有不同的类型值,我们可以通过发送消息来避免命名管道的同步和阻塞问题。
图片摘自网络文库,消息队列。
在linux内核中:内核地址空间中的内部链表,消息可以顺序地发送到队列中,并以几种不同的方式从队列中获取,每个消息队列是由IPC标识符所唯一表示的。
最常用的函数是
#include <sys/ipc.h>
int ftok(const char* path,int id)
//path 引用现有文件,产生键时,使用id的低八位
#include <sys/msg.h>
int msgget(key_t key,int flag);
功能:用来创建和访问一个消息队列
//key:表示消息队列的名字,它必须具有唯一性
//flag:用法和创建文件时mode模式标记是一样的
//返回值:成功返回一个非负整数,既该消息队列的标识码,失败返回-1
①IPC_CREAT: 如果IPC不存在,则创建一个IPC资源,否则打开操作。
②IPC_EXCL: 只有在共享内存不存在的时候,新的共享内存才建立,否则出错。如果单独使用IPC_EXCL,xxxget()函数要么返回一个已经存在的共享内存的操作符,要么返回一个新建的共享内存的标识符。
③如果IPC_CREAT和IPC_EXCL同时使用,xxxget()函数将返回一个新建的IPC标识符。如果该IPC资源已经存在,则返回-1出错。这样就保证了只有是二者同时使用,我们就可以保证所得的对象一定是新建的。
int msgctl(int msgid,int cmd,struct msgid_ds *buf);
//msgid:消息队列标识码
//cmd:要采取的动作(IPC_RMID:删除消息队列)
返回值:失败返回-1,成功返回0
int msgsnd(int msgid,const void *msgp,size_t msgsz,int msgflg);
//msgid:消息队列标识码
//msgp:是一个指针,指针指向准备发送的消息
//msgsz:发送消息长度,不包括消息类型的long int 型
//msgflg=IPC_NOWAIT表示队列满不等待,返回错误
《UNIX环境高级编程》附有详解,不一一赘述,亦可在man文档中search。
并总结:msgget error问题
编码遇到:Permission denied
msgget参数换成 IPC_CREAT | IPC_EXCL | 0666//八进制权限
msgget file error问题,
ipc查看后,关闭对应消息队列
另附ipcs -h
主要是参数问题
下面是主要comm代码段,客户端和服务器端看可执行文件和代码
static int commMsgQueue(int flags)
{
key_t _key = ftok(PATHNAME,PROJ_ID);
if(_key < 0){
perror("ftok错误");
return -1;
}
int msgid = msgget(_key,flags);
if(msgid < 0){
perror("msgget错误");
}
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)
{
struct msgbuf buf;
buf.mtype = 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 recvType,char out[])
{
struct my_msgbuf buf;
if(msgrcv(msgid,(void*)&buf,sizeof(buf.mtext),recvType,0) < 0)
{
perror("msgrcv错误");
return -1;
}
strcpy(out,buf.mtext );
return 0;
}