认识消息队列
- 消息队列提供了一个从一个进程向另外一个进程发送一块(有类型)数据的方法。
- 每个数据块都被认为是一个类型,接收者进程接收的数据块可以有不同的类型值。
- 消息队列也有管道一样的不足,就是每个消息的最大长度是有上限的(MSGMAX),就是每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有个上限(MSGMNI)。
IPC对象数据结构/usr/include/linux/ipc.h - 内核为每个IPC对象维护一个数据结构
消息队列结构/usr/include/linux/msg.h
消息队列在内核中的表示:
消息队列的函数
msgget函数
功能:用来创建和访问一个消息队列
参数:
key:某个消息队列的名字
msgflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的。
返回值:成功返回一个非负整数,即该消息队列的标识码;失败返回-1
msgctl函数
功能:消息队列的控制函数
原型
int msgctl (int msqid,int cmd,struct msqid_ds *buf);
参数:
msqid:由msgget函数返回的消息队列标识码
cmd:是将采要采取的动作,(有三个可取值)
返回值:成功返回0,失败返回-1
cmd将要采取的动作(有三个可取值),分别如下:
IPC_STAT 把msqid_ds结构中的数据设置为消息队列的当前关联值
IPC_SET 在进程有足够权限前提下,把消息队列的当前关联值设
置为msqid_ds数据结构中给出值
IPC_RMID 删除消息队列
msgsnd函数
功能:把一条消息队列添加到消息队列中
原型:
int msgsnd(int msqid,const void *msgp,size_t msgsz,int msgflg)
参数
msgid:由msgget函数返回的消息队列标识码
msgp:是一个指针,指向的是准备发送的消息
msgsz:是msgp指向的消息长度,这个长度不含保存消息类型的那个long int长整型
msflg:控制着当前消息队列满或到达系统上限时将要发生的事情。
msflg=IPC_NOWAIT表示队列满不等待,返回EAGAIN错误。
返回值:成功返回0,失败返回-1
说明:
- 消息结构方面在两方面受到制约:首先,它必须小于系统上规定的上限值
- 其次,它必须以一个long int长整型开始,接收者函数将利用这个长整数确定消息的类型。
- 2、消息结构参考形式如下:
- struct msgbuf{
long mtype;
char mtext[1];
}
msgrcv函数
功能:是从一个消息队列接收消息
原型:
ssize_t msgrcv(int msqid,void *msgp,size_t msgsz,long msgtyp,int msgflg);
参数:
msgid:由msgget函数返回消息队列标识码
msgp:是一个指针,指向准备接收的消息
msgsz:是msgp指向消息队列的长度,这个长度不含保存消息队列类型的那个long int长整型。
msgtype:它可以实现接收优先级的简单形式
msgflg:控制着队列中的没有相应类型的消息可供接收时将要发生的事
返回值:成功返回实际放到接收缓冲区里的字符个数,失败返回-1
代码实例:
我们编写的Makefile
.PHONY:all
all: client server
client:client.c comm.c
gcc -o s@ s^
sever:sever.c comm.c
gcc -o s@ s^
.PHONY:clean
clean:
rm -f client server
~
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 PATHNAME "."
#define PROJ_ID ox666
#define SERVER_TYPE 1
#define CLTENT_TYPE 2
struct msgbuf{
long mtype;
char mtext[1024];
};
int createMsgQueue();
int getMsgQueue();
int destroyMsgQueue();
int sendMsg(int msgid,int who,char *msg);
int recvMsg(int msgid,int recvType,char out[ ]);
#endif
comm.c
#include "comm.h"
2
3 //sucess >0 failed=-1
4 static int commMsgQueue(int flags)
5 {
6 key_t _key=ftok(PATHNAME,PROJ_ID);
7 if(_key<0){
8 perror("ftork");
9 return -1;
10 }
11 // int msgid=msgget(_key,IPC_CREAT|IPC_EXCL);
12 int msgid=msgget(_key,flags);
13 if(msgid<0){
14 perror("msgget");
15 }
16 return msgid;
17 }
18 int createMsgQueue(){
19 return commMsgQueue(IPC_CREAT|IPC_EXCL|0666);
20 }
21
22 int getMsgQueue()
23 {
24
25 return commMsgQueue(IPC_CREAT);
26 }
27 int destroyMsgQueue(int msgid)
28 {
29 if(msgctl(msgid,IPC_RMID,NULL)<0){
30 perror("msgctl");
31 return -1;
32 }
33 return 0;
34 }
35
36 int sendMsg(int msgid,int who,char* msg)
37 {
38 struct msgbuf buf;
39 buf.mtype=who;
40 strcpy(buf.mtext,msg);
41 if(msgsnd(msgid,(void*)&buf,sizeof(buf.mtext),0)<0){
42 perror("msgsnd");
43 return -1;
44 }
45 return 0;
46 }
47
48 int recvMsg(int msgid,int recvType,char out[]){
49 struct msgbuf buf;
50 if(msgrcv(msgid,(void*)&buf,sizeof(buf.mtext),recvType,0)<0)
51 {
52 perror("msgrcv");
53 return -1;
54 }
55 strcpy(out ,buf.mtext);
56 return 0;
57 }
58
client.c
#include "comm.h"
2
3 int main(){
4 int msgid=getMsgQueue();
5
6 int buf[1024];
7 while(1){
8 buf[0]=0;
9 printf("please enter# ");
10 fflush(stdout);
11 ssize_t s=read(0,buf,sizeof(buf));
12 if(s>0){
13 buf[s-1]=0;
14 sendMsg(msgid,CLIENT_TYPE,buf);
15 printf("sed done,wait recv...\n");
16 }
17
18 recvMsg(msgid,SERVER_TYPE,buf);
19 printf("server# %s\n",buf);
20 }
21
22 return 0;
23 }
~
server.c
#include "comm.h"
2
3 int main()
4 {
5 int msgid=createMsgQueue();
6 char buf[1024];
7 while(1)
8 {
9 buf[0]=0;
10 recvMsg(msgid,CLIENT_TYPE,buf);
11 printf("client# %s\n",buf);
12 printf("please enter# ");
13 fflush(stdout);
14 ssize_t s=read(0,buf,sizeof(buf));
15 if(s>0){
16 buf[s-1]=0;
17 sendMsg(msgid,SERVER_TYPE,buf);
18 printf("send done,wait recv...\n");
19 }
20 }
21 destroyMsgQueue(msgid);
22 return 0;
23 }
~
~
最后我们的函数运行的结果
我们发现我们在进行第一次的传输完毕之后第二次再想进行传输的时候,我们就看到
我们可以使用
最后我们再进行运行就ok了。