消息队列:
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。 每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值。我们可以通过发送消息来避免命名管道的同步和阻塞问题。消息队列与管道不同的是,消息队列是基于消息的,而管道是基于字节流的,且消息队列的读取不一定是先⼊入先出。消息队列与命名管道有一样的不足,就是每个消息的最⼤大长度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有⼀一个上限(MSGMNI)
ipc对象数据结构:
内核为每个IPC对象维护一个数据结构(/user/include/linux/ipc.h)
消息队列结构:
可以看到第一个条目就是IPC的结构体,即是共有的,后面的都是消息队列所私有的成员。
消息队列使用链表实现的。
所使用函数:
函数: key_t ftok(const char *filename, int proj_id);
通过文件名和项目号获得System V IPC键值(用于创建消息队列、共享内存所用)返回:成功返回与cmd相关的正数,错误返回-1
具体的实现过程如下:
comm.h
#ifndef _COMM_H_
#define _COMM_H_
#include
#include
#include
#include
#include
#define PATHNAME "."
#define PROJ_ID 0x6666
#define SERVER_TYPE 1
#define CLIENT_TYPE 2
#define SIZE 128
struct msgbuf{
long mtype;
char mtext[SIZE];
};
int creatMsgQueue();
int getMsgQueue();
int sendMsg(int msgid,long type,const char*_info);
int recvMsg(int msgid,long type,char out[]);
int destoryMsgQueue(int);
#endif
comm.c
#include"comm.h"
int commMsgQueue(int flags)
{
key_t _k=ftok(PATHNAME,PROJ_ID);
if(_k<0)
{
perror("ftok");
return -1;
}
int msg_id = msgget(_k,flags);
if(msg_id<0)
{
perror("msg");
return -2;
}
return msg_id;
}
int creatMsgQueue()
{
return commMsgQueue(IPC_CREAT|IPC_EXCL|0666);
}
int getMsgQueue()
{
return commMsgQueue(IPC_CREAT);
}
int destoryMsgQueue(int msgid)
{
if(msgctl(msgid,IPC_RMID,NULL)<0)
{
perror("fail\n");
return -1;
}
}
int sendMsg(int msgid,long type,const char*_info)
{
struct msgbuf msg;
msg.mtype = type;
strcpy(msg.mtext,_info);
if( msgsnd(msgid,&msg,sizeof(msg.mtext),0)<0)
{ perror("msgsnd");
return -1;
}
return 0;
}
int recvMsg(int msgid,long type,char out[])
{
struct msgbuf msg;
if(msgrcv(msgid,&msg,sizeof(msg.mtext),type,0)<0)
{
perror("msgrecv");
return -1;
}
strcpy(out,msg.mtext);
return 0;
}
client.c
#include"comm.h"
int main()
{
int msgid=getMsgQueue();
printf("msgid:%d\n",msgid);
char buf[SIZE];
while(1)
{
//send->recv
printf("please Enter$");
fflush(stdout);
ssize_t s=read(0,buf,sizeof(buf)-1);
if(s>0)
{
buf[s-1]='\0';
sendMsg(msgid,CLIENT_TYPE,buf);
}
recvMsg(msgid,SERVER_TYPE,buf);
printf("server# %s\n",buf);
}
return 0;
}
server.c
#include"comm.h"
int main()
{
int msgid=creatMsgQueue();
printf("msgid: %d\n",msgid);
char buf[SIZE];
while(1)
{
recvMsg(msgid,CLIENT_TYPE,buf);
printf("client# %s\n",buf);
fflush(stdout);
ssize_t s=read(0,buf,sizeof(buf)-1);
if(s>0)
{
buf[s-1]='\0';
sendMsg(msgid,SERVER_TYPE,buf);
}
}
deseoryMsgQueue(msgid);
return 0;
}
ipcs -q可查看存在的消息队列
ipcrm -q +msgid 可删除该消息队列