unix早期通信机制之一的信号能够传送的信息量有限,管道则只能传送无格式的字节流,这无疑会给应用程序开发带来不便。消息队列(也叫做报文队列)则克服了这些缺点。
消息队列就是一个消息的链表.可以把消息看作一个记录,具有特定的格式.进程可以向中按照一定的规则添加新消
息;另一些进程则可以从消息队列中读走消息
目前主要有两种类型的消息队列:
POSIX消息队列以及系统V消息队列,系统V消息队列目前被大量使用
持续性:
系统V消息队列是随内核持续的,只有在内核重起或者人工删除时,该消息队列才会被删除
键值:
消息队列的内核持续性要求每个消息队列都在系统范围内对应唯一的键值,所以,要获得一个消息队列
的描述字,必须提供该消息队列的键值
下面是消息队列相关的函数:
msgget
函数作用:创建消息队列
函数原型:int msgget(key_t key,int msgflag)
函数参数: key:键值;IPC_PRIVATE设定一个数字,也可以由ftok获得
msgflag:权限,同open函数
返回值:成功返回消息队列ID,出错-1
头文件: #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
键值ftok:
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok (char*pathname, char proj)
功能: 返回文件名对应的键值。
pathname: 文件名
proj: 项目名(不为0即可)
msgsnd
函数作用:些数据到消息队列
函数原型:int msgsnd(int misgid,const void *msggp,size_t msgsize,int msgflag)
函数参数:msggp 消息结构 struct msgbuf
{
long msgtype;
char mtext[1];
}
msgsize:消息的字节数
msgflag:IPC_NOWAIT:写不进去消息直接返回
0:一直等待到能写进消息为止
返回值:成功0,出错-1
msgctl:
函数作用:控制消息队列,可删除消息队列
函数原型:int msgctl(int msgid,int cmd,struct msgid_ds *buf)
函数参数:cmd:IPC_STAT:读取消息队列的结构,存储在buf指定的地址中
:IPC_SET:设置消息队列的权限
:IPC_RMID:删除消息队列
buf:消息队列 的结构类型变量
返回值:成功0,出错-1
下面是个简单的例子:
功能:a向b发送消息后,b接收后可以向a发送,如此往复,直到输入end结束。
该功能由两个程序实现
程序1:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MAX_TEXT 512
struct my_msg_st
{
long int my_msg_type;
char some_text[BUFSIZ];
};
int main(void)
{
int running = 1;
int msgid;
struct my_msg_st some_data;
long int msg_to_receive=0;
char buffer[BUFSIZ];
/*创建消息队列*/
msgid=msgget((key_t)1234,0666 | IPC_CREAT);
if(msgid==-1)
{
fprintf(stderr,"msgget failed with error: %d\n",errno);
exit(EXIT_FAILURE);
}
/*循环从消息队列中接收消息*/
while(running)
{
/*向消息队列写*/
printf("enter some text:");
fgets(buffer,BUFSIZ,stdin);
some_data.my_msg_type = 1;
strcpy(some_data.some_text,buffer);
if(msgsnd(msgid,(void *)&some_data,MAX_TEXT,0) == -1)
{
fprintf(stderr,"msgsen failed!\n");
exit(EXIT_FAILURE);
}
//sleep(2);
/*读取消息*/
if(msgrcv(msgid,(void *)&some_data,BUFSIZ,msg_to_receive + 5,0)==-1)
{
}
fprintf(stderr,"msgrcv failed with error: %d\n",errno);
exit(EXIT_FAILURE);
}
printf("You wrote: %s",some_data.some_text);
/*接收到的消息为“end”时结束循环*/
if(strncmp(some_data.some_text,"end",3)==0)
{
running=0;
}
}
/*从系统内核中移走消息队列*/
if(msgctl(msgid,IPC_RMID,0)==-1)
{
fprintf(stderr,"msgctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
程序b:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MAX_TEXT 512
struct my_msg_st
{
long int my_msg_type;
char some_text[MAX_TEXT];
};
int main(void)
{
int running = 1;
int msgid;
long int msg_to_receive = 0;
struct my_msg_st some_data;
char buffer[BUFSIZ];
//创建消息队列
msgid = msgget((key_t)1234,0666 | IPC_CREAT);
if(-1 == msgid)
{
fprintf(stderr,"msgget failed!\n");
exit(EXIT_FAILURE);
}
//循环向消息队列中写
while(running)
{
//读
if(msgrcv(msgid,(void *)&some_data,BUFSIZ,msg_to_receive,0) == -1)
{
fprintf(stderr,"msgsen failed!\n");
exit(EXIT_FAILURE);
}
printf("You wrote:%s",some_data.some_text);
//sleep(2);
printf("Enter some text:");
fgets(buffer,BUFSIZ,stdin);
some_data.my_msg_type = 5;
strcpy(some_data.some_text,buffer);
//写消息
if(msgsnd(msgid,(void *)&some_data,MAX_TEXT,0) == -1)
{
fprintf(stderr,"msgsed failed\n");
exit(EXIT_FAILURE);
}
//用户输入end时结束循环
if(strncmp(buffer,"end",3) == 0)
{
running = 0;
}
}
exit(EXIT_SUCCESS);
}
若想要想QQ等聊天软件一样收发消息自如,只需在上述条件下用父子进程来实现,后续会补上程序...