您的位置:首页 > 其它

进程间通信之消息队列

2016-04-18 21:02 218 查看
一.对消息队列的理解
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。通过发送消息来避免命名管道的同步与阻塞问题。
消息队列与管道的不同之处在于:消息队列是基于消息的,而管道是基于字节流的;而且消息队列的读取不一定是先入先出。
消息队列与命名管道有一样的不足:每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也是有上限的(MSGMNI)。
二.相关的函数
(1)创建新消息队列或取得已存在消息队列。
函数原型:int msgget(key_t key,int msgflg);
参数:
key :可以认为是一个端口号,也可以由函数ftok产生;
msgflg:
IPC_CREAT:如果IPC 不存在,则创建一个IPC资源,否则打开操作。当单独使用IPC_CREAT时,XXXget()函数要么返回一个已经存在的共享内存的操作符,要么返回一个新建的共享内存的标识符。
IPC_EXCL:只有在共享内存不存在的时候,新的共享内存才建立,否则就会产生错误。IPC_EXCL标志本身没有太大的意义,但和IPC_CREAT标志一起使用可以保证所得的对象是新建的,而不是打开已有的对象。
如果将IPC_CREAT和IPC_EXCL标志一起使用,XXXGET()函数将返回一个新建的IPC标识符;如果该IPC 资源已存在,返回-1。
(2)向队列读或写消息
从队列中取消息的函数原型:ssize_t msgrcv(int msqid,void *msgp,size_t msgsz,
long msgtyp,int msgflg);

将数据放到消息队列中的函数原型:int msgsnd(int msgid,const void *msgp,size_t msgsz,
int msgflg);

参数:

msqid:消息队列的标识码

msgp:指向消息缓冲区的指针,用来暂时存储发送和接收的消息,是一个用户可定义的通用结构,形态如下:

struct msgstru{

long mtype;

char mtext[用户指定大小];

};

msgsz:消息的大小。

magtyp:从消息队列中读取的消息形态。如果值为0,表示消息队列中的所有消息都会被读取。

msgflg:用来指明核心程序在队列没有数据的情况下所应采取的行动。

(3)设置消息队列属性
函数原型:int msgctl(int msgqid,int cmd,struct msqid_ds *buf);

参数:msgctl系统调用对msgqid标志的消息队列执行cmd操作,系统定义了三种cmd操作:

IPC_STAT,IPC_SET,IPC_RMID
IPC_STAT:用来获取消息队列对应的msqid_ds数据结构,并将其保存在buf指定的地址空间。

IPC_SET:用来设置消息队列的属性,要设置的属性存储在buf中。

IPC_RMID:从内核中删除msqid标志的消息队列。
三.代码
comm.h
1 #pragma once

2 #include<stdio.h>
3 #include<stdlib.h>
4 #include<string.h>
5 #include<sys/types.h>
6 #include<unistd.h>
7 #include<sys/ipc.h>
8 #include<sys/msg.h>
9 #define _PATH_ "."
10 #define _PROJ_ID_ 0x4444
11 #define _BLOCK_SIZE_ 1024
12 #define _SERVER_MSG_TYPE_ 1
13 #define _CLIENT_MSG_TYPE_ 2
14 struct msgbuf
15 {
16 long mtype;
17 char mtext[_BLOCK_SIZE_];
18 };
19 static int comm_msg_queue(int flag);
20 int set_msg_queue();
21 int get_msg_queue();
22 int msg_queue_send(int msg_id,const char* _info,int _mtype);
23 int msg_queue_recv(int msg_id,char* buf,int recv_type);
24 int destroy_msg_queue(int msg_id);

comm.c
1 #include "comm.h"
2
3 static int comm_msg_queue(int flag)
4 {
5 key_t _key=ftok(_PATH_,_PROJ_ID_);
6 if(_key<0)
7 {
8 perror("ftok");
9 return -1;
10 }
11 int msg_id=msgget(_key,flag);
12 if(msg_id<0)
13 {
14 perror("msgget");
15 return -1;
16 }
17 return msg_id;
18 }
19 int set_msg_queue()
20 {
21 umask(0);
22 return comm_msg_queue(IPC_CREAT|IPC_EXCL|0666);
23 }
24 int get_msg_queue()
25 {
26 return comm_msg_queue(IPC_CREAT);
27 }
28 int msg_queue_send(int msg_id,const char *_info,int _mtype)
29 {
30 struct msgbuf _msg;
31 _msg.mtype=_mtype;
32 memset(_msg.mtext,'\0',sizeof(_msg.mtext));
33 strcpy(_msg.mtext,_info);
34 if(msgsnd(msg_id,&_msg,sizeof(_msg.mtext),0)<0)
35 {
36 perror("msgsnd");
37 return -1;
38 }
39 return 0;
40 }
41 int msg_queue_recv(int msg_id,char* buf,int recv_type)
42 {
43 struct msgbuf _msg;
44 if(msgrcv(msg_id,&_msg,sizeof(_msg.mtext),recv_type,0)<0)
45 {
46 perror("msgrcv");
47 return -1;
48 }
49 strcpy(buf,_msg.mtext);
50 return 0;
51 }
52 int destroy_msg_queue(int msg_id)
53 {
54 if(msgctl(msg_id,IPC_RMID,NULL)<0)
55 {
56 perror("msgctl");
57 return -1;
58 }
59 else
60 {
61 printf("remove msg queue done...\n");
62 }
63 return 0;
64 }

my_server.c
1 #include "comm.h"
2 int main()
3 {
4 int msgid=set_msg_queue();
5 if(msgid<0)
6 {
7 printf("get msgid fail\n");
8 exit(1);
9 }
10 char buf[_BLOCK_SIZE_];
11 printf("intput quit endding...\n");
12 while(1)
13 {
14 if(msg_queue_recv(msgid,buf,_CLIENT_MSG_TYPE_)<0)
15 {
16 printf("recv fail\n");
17 exit(1);
18 }
19 else
20 {
21 if(strcmp("quit",buf)==0)
22 {
23 return 0;
24 }
25 printf("client:%s\n",buf);
26 }
27 printf("input:");
28 fflush(stdout);
29 memset(buf,'\0',_BLOCK_SIZE_);
30 gets(buf);
31 if(msg_queue_send(msgid,buf,_SERVER_MSG_TYPE_)<0)
32 {
33 printf("send fail\n");
34 exit(1);
35 }
36 }
37 // destroy_msg_queue(msgid);
38 return 0;
39
40 }

client.c
1 #include "comm.h"
2 int main()
3 {
4 int msgid=get_msg_queue();
5 if(msgid<0)
6 {
7 exit(1);
8 }
9 char buf[_BLOCK_SIZE_];
10 while(1)
11 {
12 fflush(stdout);
13 printf("please input:");
14 memset(buf,'\0',_BLOCK_SIZE_);
15 gets(buf);
16 if(msg_queue_send(msgid,buf,_CLIENT_MSG_TYPE_)<0)
17 {
18 printf("send fail\n");
19 exit(1);
20 }
21 if(msg_queue_recv(msgid,buf,_SERVER_MSG_TYPE_)<0)
22 {
23 printf("recv fail\n");
24 exit(1);
25 }
26 printf("sever:%s\n",buf);
27 }
28 destroy_msg_queue(msgid);
29 return 0;
30 }

makefile:
1 .PHONY:all
2 all:my_server client
3 my_server:my_server.c comm.c
4 gcc -o $@ $^
5 client:client.c comm.c
6 gcc -o $@ $^
7 .PHONY:clean
8 clean:
9 rm -f my_server client

四.运行结果


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  消息队列