消息队列是操作系统为两个无关进程准备的通信方式,每个消息队列都有一个他自己的ID我们用来标识消息队列
消息队列的不足就是我们发送消息的
最大长度有限制,并且操作系统提供的
消息队列的个数也是有限的
此ID用如下函数创建
此函数中的path为一个路径,讲道理这个路径其实可以随便定义,一般定义成当前目录即可,然后这个proj_id就是一个数字而已可以随便设,啊就是这样,但是我们要知道同一个路径同一个项目ID数完全有可能产生同一个消息队列ID的,并且我们要注意的是消息队列和管道不一样,管道的生命随进程,但是消息队列的生命随操作系统,所以当我们创建了一个新的消息队列的话一定要手动的去销毁,不然再次创建的话就有可能会失败,那么这我们介绍两个命令
ipcs -q:查看所有的消息队列
ipcrm -q id:删除id的消息队列
那现在我们知道创建消息队列失败的原因:
-
操作系统的消息队列的数目已达上限
-
创建的此消息队列的ID已被占用
那我们用消息队列来写一个
服务器和客户端的相互通信
首先是关于消息队列的一系列的函数
comm.h
#ifndef _COMM_H_
#define _COMM_H_
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>
#define PATH_NAME "/tmp"
#define PROJ_ID 0x6666
//创建消息队列
#define SERVER_TYPE 1
#define CLIENT_TYPE 2
//此时我们用msgbuf是显示重定义
//应该是在头文件里的msg缓冲区定义为msgbuf
//我们将我们的名字换一下即可
struct msgbuff
{
long mtype;
char mtext[128];
};
int createMsgQueue();
//创建消息队列
int getMsgQueue();
//获得消息队列
int sendMsg(int msgid,char *msg,int t);
//发送消息队列
//接受消息队列
int recvMsg(int msgid,char *msg,int t);
//销毁消息队列
void destoryMsgQueue(int msgid);
#endif
comm.c
#include "comm.h"
int commMsgQueue(int flag)
{
key_t k = ftok(PATH_NAME,PROJ_ID);
if(k < 0)
{
printf("ftok error!!");
return -1;
}
int msgid = msgget(k,flag);
if(msgid < 0)
{
printf("msgget error!!");
return -2;
}
return msgid;
}
int createMsgQueue()
{
return commMsgQueue(IPC_CREAT|IPC_EXCL|0644);
}
int getMsgQueue()
{
return commMsgQueue(IPC_CREAT);
}
void destoryMsgQueue(int msgid)
{
if(msgctl(msgid,IPC_RMID,NULL) < 0)
{
printf("msgctl error!!");
}
}
//发送数据块
//msgid(消息队列的标识符),msg(数据块结构体的地址),
//msgsz(数据块里数组的字节大小),msgflg(判断是阻塞式还是非阻塞式)
//int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
int sendMsg(int msgid,char *msg,int t)
{
struct msgbuff buf;
buf.mtype = t;
strcpy(buf.mtext,msg);
if(msgsnd(msgid,&buf,sizeof(buf.mtext),0) < 0)
{
printf("msgsnd error!\n");
return -1;
}
return 0;
}
//接收数据块
//msgtyp(数据块内容的类型)
//ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
//msg:要发送的数据
int recvMsg(int msgid,char *msg,int t)
{
struct msgbuff buf;
if(msgrcv(msgid,&buf,sizeof(buf.mtext),t,0) < 0)
{
perror("msgrcv error!\n");
return -1;
}
strcpy(msg,buf.mtext);
return 0;
}
接下来是我们的服务器和客户端的代码
因为服务器端是先接受消息,再发送消息
//server.c
#include"comm.h"
int main()
{
int msgid = createMsgQueue();
//printf("%d",msgid);
char buf[256];
while(1)
{
if(strcmp(buf,"quit") == 0)
{
printf("client quit\n");
break;
}
recvMsg(msgid,buf,CLIENT_TYPE);
printf("client #%s\n",buf);
printf("Please enter:");
scanf("%s",buf);
sendMsg(msgid,buf,SERVER_TYPE);
}
destoryMsgQueue(msgid);
return 0;
}
客户端是先发送消息再接收消息
//client.c
#include"comm.h"
int main()
{
int msgid = getMsgQueue();
//先发消息
char buf[256];
while(1)
{
printf("Please enter :");
scanf("%s",buf);
sendMsg(msgid,buf,CLIENT_TYPE);
if(strcmp("quit",buf) == 0)
{
printf("client quit!");
}
recvMsg(msgid,buf,SERVER_TYPE);
printf("server #%s\n",buf);
}
destoryMsgQueue(msgid);
return 0;
}