一.消息队列概念
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。每个数据块都被认为是有一个类型的,接收者进程接收的数据块可以有不同的类型值。我们可以发送消息来避免命名管道的同步和阻塞。消息队列与管道不同的是,消息队列是基于消息的,而管道是基于字节流的,且消息队列的读取不一定是先入先出的,消息队列与命名管道有一样的不足,就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI)
二.消息队列的特点
(1)消息队列是消息的链表,具有特定的格式存放在内存中,并有消息队列标识符标识
(2)消息队列的生命周期随内核。
(3)消息队列是基于消息的。
(4)消息队列可以实现双向通信。
(5)消息队列允许一个或多个进程向它写入与读取消息
三,消息队列的的接口
1,创建新消息队列或取得已存在消息队列
参数说明:
第一个参数key,可以认为是一个端口号,也可以由ftok函数生成,它是唯一标识ipc资源,这里的key由ftork函数调用生成。
第二个参数msgflg有两个标志。IPC_CREAT和IPC_EXCL,当IPC_CREAT单独使用时,若IPC不存在,则创建一个IPC资源,如果存在,则打开并返回。如果将IPC_CREAT和IPC_EXCL按或使用,XXXget()将返回一个新建的IPC标识符,如果该IPC已经存在,返回-1.
2.向队列读/写消息
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
//将数据放到消息队列中
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
//从队列中取消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
参数解析:
msqid:消息队列标识码(不解释)
msgp:指向消息缓冲区的指针,此位置用来暂时存储发送和接收的消息,是一个用户可定义的通用结构,如下
struct msgstru
{
long mtype;//大于0;
char mtext[用户指定大小];
}
msgsz:消息的大小
msgtyp:消息的类型,用来识别消息是谁发的。
msgflg:消息接收方式,有阻塞和非阻塞方式。
3.设置消息队列属性
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参数解释:
msg系统调用对msgqid标识的消息队列执行cmd操作,系统定义了3中cmd操作:IPC_STAT,IPC_SET,IPC_RMID
IPC_STAT:用来获取消息队列对应的msgqid_ds数据结构,将其保存在 buf 指定的地址空间。
IPC_SET :用来设置消息队列中的属性,要设置的属性存在 buf 中
IPC_RMID:从内核中删除msgqid标识的消息队列。
四,消息队列代码实现
comm.h
1 #ifndef __COMM__
2 #define __COMM__
3
4 #include <stdio.h>
5 #include <sys/ipc.h>
6 #include <sys/msg.h>
7 #include <sys/types.h>
8 #include <string.h>
9 #include <stdlib.h>
10
11 #define FILENAME "."
12 #define PROJ_ID 0x6666
13
14 #define SERVER_TYPE 1
15 #define CLIENT_TYPE 2
16 struct _msginfo
17 {
18 long mtype;
19 char mtext[1024];
20 };
21 int CreatMsgQuenu();//创建消息队列
22 int GetMsgQuenu();//获取消息队列
23 int DestroyMsgQueue(int msgid);//销毁消息队列
24 int SendMsg(int msgid,int type,const char* msg);//向消息队列里发送数据
25 int RecvMsg(int msgid,int type,char* out);//从消息队列里取数据
26 #endif
comm.c
1 #include "comm.h"
2 static int commMsgQueue(int flags)
3 {
4 key_t _key = ftok(FILENAME,PROJ_ID);
5 if (_key <0)
6 {
7 perror("ftok\n");
8 return -1;
9 }
10
11 int msgid = msgget(_key,flags);
12 if (msgid <0)
13 {
14 perror("msgget\n");
15 return -2;
16 }
17 return msgid;
18 }
19
20 int CreatMsgQueue()
45 }
46 strcpy(out,msginfo.mtext);
47 return 0;
48 }
49 int SendMsg(int msgid,int type,const char* msg)
50 {
51 struct _msginfo msginfo;
52 msginfo.mtype = type;
53 strcpy(msginfo.mtext,msg);
54 if (msgsnd(msgid,&msginfo,sizeof(msginfo.mtext),0)<0)
55 {
56 perror("msgsnd\n");
57 return -1;
58
59 }
60 return 0;
61 }
62
msg_server.c
#include "comm.h"
2
3 int main()
4 {
5 int msgid = CreatMsgQueue();
1 #include "comm.h"
2
3 int main()
4 {
5 int msgid = CreatMsgQueue();
6 char buf[1024];
7 while(1)
8 {
9 buf[0] = 0;
10 RecvMsg(msgid,CLIENT_TYPE,buf);
11 printf("client say#%s\n",buf);
12 printf("server enter#");
13 fflush(stdout);//使上面那句话刷新的屏幕上
14 ssize_t s = read(0,buf,sizeof(buf)-1);
15 if (s>0)
16 {
17 buf[s-1] = 0;
18 SendMsg(msgid,SERVER_TYPE,buf);
19 }
20 }
21 DestroyMsgQueue(msgid);
22 return 0;
23 }
msg_client.c
#include "comm.h"
2
3 int main()
4 {
5 int msgid = GetMsgQueue();
6 char buf[1024];
7 while(1)
8 {
9 buf[0] = 0;
10 printf("client enter#");
11 fflush(stdout);
12
13 ssize_t s = read(0,buf,sizeof(buf)-1);
14 if (s>0)
15 {
16 buf[s-1] = 0;
17 SendMsg(msgid,CLIENT_TYPE,buf);
18 }
19 RecvMsg(msgid,SERVER_TYPE,buf);
20 printf("server say# %s\n",buf);
21
22 }
23 return 0;
24 }
运行结果:
五,相关指令
(1),查看消息队列 ipcs -q msqid
(2),删除系统的消息队列 ipcrm -q msqid