消息队列
消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
1.特点
1.消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
2.消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
3.消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取
函数原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
/* 创建或打开消息队列:成功返回队列ID,失败-1*/
int msgget(key_t key, int msgflg);
第二个参数,msgflg 控制的。它可以取下面的几个值:
IPC_CREAT :
如果消息队列对象不存在,则创建之,否则则进行打开操作;
IPC_EXCL:
和IPC_CREAT 一起使用(用”|”连接),如果消息对象不存在则创建之,否则产生一个
错误并返回。
/* 添加消息:成功返回0, 失败-1*/
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
msqid:队列ID
*msgp:msgp 指向要发送的消息所在的内存
msgsz:是要发送信息的长度(字节数)
msgflg:第四个参数是控制函数行为的标志,可以取以下的值:0,忽略标志位;
/* 读取消息:成功返回消息数据的长度, 失败-1*/
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
函数的前三个参数和msgsnd()函数中对应的参数的含义是相同的。第四个参数mtype
指定了函数从队列中所取的消息的类型
第五个参数依然是是控制函数行为的标志,取值可以是:0,表示忽略;
/* 控制消息队列:成功返回0,失败-1*/
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
函数的第一个参数msgqid 是消息队列对象的标识符。
第二个参数是函数要对消息队列进行的操作,它可以是:
**IPC_STAT**
取出系统保存的消息队列的msqid_ds 数据,并将其存入参数buf 指向的msqid_ds 结构
中。
**IPC_SET**
设定消息队列的msqid_ds 数据中的msg_perm 成员。设定的值由buf 指向的msqid_ds
结构给出。
**IPC_RMID**
将队列从系统内核中删除。
下面用到ftok函数
系统建立IPC通讯 (消息队列、信号量和共享内存) 时必须指定一个ID值。通常情况下,该id值通过ftok函数得到。
头文件
#include <sys/types.h>
#include <sys/ipc.h>
函数原型:
key_t ftok( const char * fname, int id )
fname就是你指定的文件名(已经存在的文件名),一般使用当前目录,如:
key_t key;
key = ftok(".", 1); 这样就是将fname设为当前目录。
id是子序号。虽然是int类型,但是只使用8bits(1-255)。
在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值。
如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。
查询文件索引节点号的方法是: ls -i
当删除重建文件后,索引节点号由操作系统根据当时文件系统的使用情况分配,因此与原来不同,所以得到的索引节点号也不同。
字符的输入与输出使用gets()和puts()的原因:scanf输入字符串(含有空格的字符串,例如:“I love you!”)时,总是在空格处停止扫描
简单的demo:server端可以发送消息给client端,client端可以实时获取打印到终端显示
msg_client.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <string.h>
#define MSG_FILE "/etc/passwd"
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[256]; /* message data */
};
int main()
{
int msg_ID;
key_t key;
key = ftok(MSG_FILE,'z');
if(key < 0){
printf("ftok errr!!\n");
}
printf("ket :%d\n",key);
msg_ID = msgget(key,IPC_CREAT|0777);
if(msg_ID == -1){
printf("msgget error!!\n");
perror("why");
exit(-1);
}
struct msgbuf msg_client;
msg_client.mtype = 888;
while(1){
msgrcv(msg_ID,&msg_client,sizeof(msg_client.mtext),msg_client.mtype,0);
//printf("client read_buff:%s\n",msg_client.mtext);
printf("read form server:");
puts(msg_client.mtext);
memset(msg_client.mtext,0,sizeof(msg_client.mtext));
}
return 0;
}
msg_server.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#define MSG_FILE "/etc/passwd"
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[256]; /* message data */
};
int main()
{
key_t key = ftok(MSG_FILE,'z');
if(key < 0){
printf("ftok error!!\n");
exit(-1);
}
printf("key:%d\n",key);
int msg_ID;
msg_ID = msgget(key,IPC_CREAT|0777);
if(msg_ID == -1){
printf("msgget error!!\n");
perror("why");
exit(-1);
}
struct msgbuf server;
server.mtype = 888;
while(1){
gets(server.mtext);
msgsnd(msg_ID,&server,sizeof(server.mtext),0);
memset(server.mtext,0,sizeof(server.mtext));
}
return 0;
}
效果大概就这样: