System V 消息队列 - 复用消息
消息队列中的消息结构可以由我们自由定义,具备较强的灵活性。通过消息结构可以共享一个队列,进行消息复用。通常定义一个类似如下的消息结构:

#define MSGMAXDAT 1024
struct mymsg
{
long msg_len; //消息长度
long msg_type; //消息类型
long msg_data[MSGMAXDATA]; //消息内容
};

消息结构相关联的类型字段(msg_type)提供了两个特性:
(1)标识消息,使得多个进程在单个队列上复用消息。
(2)用作优先级字段,允许接收者以不同于先进先出的某个顺序读出各个消息。
例子1:每个应用一个队列,可以在多个客户和单个服务器之间复用消息。使用一个消息队列进行通信,由消息类型标识消息是从客户到服务器,还是服务器到客户。通信模型如下:
按照通信模型编写程序如下:
公共头文件svmsg.h
1 #ifndef SVMSG_H
2 #define SVMSG_H
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include <sys/types.h>
8 #include <sys/ipc.h>
9 #include <sys/msg.h>
10 #include <errno.h>
11
12 #define MSG_R 0400 /* read permission */
13 #define MSG_W 0200 /* write permission */
14 #define SVMSG_MODE (MSG_R | MSG_W | MSG_R >>3 | MSG_R >>6)
15 #define MQ_KEY 1234L
16 #define MSGMAX 1024
17 //消息结构
18 struct mymesg
19 {
20 long mesg_len;
21 long mesg_type;
22 char mesg_data[MSGMAX];
23 };
24 #endif
客户端程序sysv_client.c
1 #include "svmsg.h"
2 void client(int ,int);
3
4 int main(int argc,char *argv[])
5 {
6 int msqid;
7 if((msqid = msgget(MQ_KEY,0)) == -1)
8 {
9 perror("megget()");
10 exit(-1);
11 }
12 client(msqid,msqid);
13 exit(0);
14 }
15
16 void client(int readfd,int writefd)
17 {
18 size_t len;
19 ssize_t n;
20 char *ptr;
21 struct mymesg mesg;
22 printf("Send request to server.\n");
23 //set pid to message
24 snprintf(mesg.mesg_data,MSGMAX,"%ld",(long)getpid());
25 len = strlen(mesg.mesg_data);
26 mesg.mesg_data[len] = ' '; //blank
27 ptr = mesg.mesg_data+len+1;
28 printf("Enter filename: ");
29 fgets(ptr,MSGMAX-len,stdin);
30 len = strlen(mesg.mesg_data);
31 if(mesg.mesg_data[len-1] == '\n')
32 len--;
33 mesg.mesg_len = len;
34 mesg.mesg_type = 1;
35 printf("mesg_data is :%s len=%ld\n",mesg.mesg_data, mesg.mesg_len);
36 if(msgsnd(writefd,&(mesg.mesg_type),mesg.mesg_len,0) == -1)
37 {
38 perror("msgsnd() error");
39 exit(-1);
40 }
41 //read from IPC,write to standard output
42 mesg.mesg_type = getpid();
43 while( (n = msgrcv(readfd,&(mesg.mesg_type),MSGMAX,mesg.mesg_type,0))>0)
44 {
45 write(STDOUT_FILENO,mesg.mesg_data,n);
46 putchar('\n');
47 }
48 if(n == 0 )
49 {
50 printf("Read file from server is completed.\n");
51 }
52 if(n == -1)
53 {
54 perror("msgrcv() error");
55 exit(-1);
56 }
57 }
服务器程序sysv_server.c
1 #include "svmsg.h"
2 void server(int ,int);
3 int main(int argc,char *argv[])
4 {
5 int msqid;
6 if((msqid = msgget(MQ_KEY,SVMSG_MODE | IPC_CREAT)) == -1)
7 {
8 perror("megget()");
9 exit(-1);
10 }
11 server(msqid,msqid);
12 exit(0);
13 }
14
15 void server(int readfd,int writefd)
16 {
17 FILE *fp;
18 char *ptr;
19 pid_t pid;
20 ssize_t n;
21 ssize_t len;
22 struct mymesg mesg;
23 printf("Waiting for client......\n");
24 for(; ;)
25 {
26 mesg.mesg_type = 1;
27 if((n = msgrcv(readfd,&(mesg.mesg_type),MSGMAX,mesg.mesg_type,0)) == 0)
28 {
29 printf("pathname missing.\n");
30 continue;
31 }
32 mesg.mesg_data[n] = '\0';
33 printf("Received message from client is: %s\n",mesg.mesg_data);
34 if ((ptr = strchr(mesg.mesg_data,' ')) == NULL)
35 {
36 printf("bogus request: %s\n",mesg.mesg_data);
37 continue;
38 }
39 *ptr++ = 0;
40 pid = atoi(mesg.mesg_data);
41 mesg.mesg_type = pid;
42 //open fiel and read data
43 if((fp = fopen(ptr,"r")) == NULL)
44 {
45 printf("open file failed.sent msg to client\n");
46 snprintf(mesg.mesg_data+n,sizeof(mesg.mesg_data)-n,": can't open,%s\n",strerror(errno));
47 mesg.mesg_len = strlen(ptr);
48 memmove(mesg.mesg_data,ptr,mesg.mesg_len);
49 if(msgsnd(writefd,&(mesg.mesg_type),mesg.mesg_len,0) == -1)
50 {
51 perror("msgsnd() error");
52 exit(-1);
53 }
54 }
55 else
56 {
57 printf("open file successed.sent file to client\n");
58 while(fgets(mesg.mesg_data,MSGMAX,fp) != NULL)
59 {
60 mesg.mesg_len = strlen(mesg.mesg_data);
61 if(msgsnd(writefd,&(mesg.mesg_type),mesg.mesg_len,0) == -1)
62 {
63 perror("msgsnd() error");
64 exit(-1);
65 }
66 }
67 fclose(fp);
68 }
69 printf("send compelted.\n");
70 mesg.mesg_len = 0;
71 if(msgsnd(writefd,&(mesg.mesg_type),mesg.mesg_len,0) == -1)
72 {
73 perror("msgsnd() error");
74 exit(-1);
75 }
76 }
77 }
程序测试结果如下所示:

例子2:每个客户一个队列,将例子1改成所有用户用一个共同的消息队列向服务器发送消息,给每个客户分配一个消息队列,使得服务器对每个客户进行应答。通信模型如下:
以并发服务器模型编写这个程序,服务器给每个客户fork一个子进程进行处理。程序如下:
公共头文件svmsg.h和svmsg.c:
1 //svmsg.h file
2 #ifndef SVMSG_H
3 #define SVMSG_H
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <signal.h>
9 #include <sys/types.h>
10 #include <sys/ipc.h>
11 #include <sys/msg.h>
12 #include <errno.h>
13
14 #define MSG_R 0400 /* read permission */
15 #define MSG_W 0200 /* write permission */
16 #define SVMSG_MODE (MSG_R | MSG_W | MSG_R >>3 | MSG_R >>6)
17 #define MQ_KEY 1234L
18 #define MSGMAX 1024
19 //message structure
20 struct mymesg
21 {
22 long mesg_len;
23 long mesg_type;
24 char mesg_data[MSGMAX];
25 };
26
27 ssize_t mesg_send(int id,struct mymesg *mptr);
28 ssize_t mesg_recv(int id,struct mymesg *mptr);
29
30 void Mesg_send(int id,struct mymesg *mptr);
31 ssize_t Mesg_recv(int id,struct mymesg *mptr);
32 #endif
1 //svmsg.c file
2 #include "svmsg.h"
3
4 ssize_t mesg_send(int id,struct mymesg *mptr)
5 {
6 return (msgsnd(id,&(mptr->mesg_type),mptr->mesg_len,0));
7 }
8
9 ssize_t mesg_recv(int id,struct mymesg *mptr)
10 {
11 ssize_t n;
12 n = msgrcv(id,&(mptr->mesg_type),MSGMAX,mptr->mesg_type,0);
13 mptr->mesg_len = n;
14 return n;
15 }
16
17 void Mesg_send(int id,struct mymesg *mptr)
18 {
19 if(mesg_send(id,mptr) == -1)
20 {
21 perror("mesg_send() error");
22 exit(-1);
23 }
24 }
25 ssize_t Mesg_recv(int id,struct mymesg *mptr)
26 {
27 ssize_t n;
28 do
29 {
30 n = mesg_recv(id,mptr);
31 }while(n==-1 && errno == EINTR);
32 if(n == -1)
33 {
34 perror("mesg_recv() error");
35 exit(-1);
36 }
37 return n;
38 }
客户端程序如下:
1 #include "svmsg.h"
2
3 void client(int ,int);
4
5 int main(int argc,char *argv[])
6 {
7 int readid,writeid;
8 if((writeid = msgget(MQ_KEY,0)) == -1)
9 {
10 perror("megget()");
11 exit(-1);
12 }
13 if((readid = msgget(IPC_PRIVATE,SVMSG_MODE | IPC_CREAT)) == -1)
14 {
15 perror("megget()");
16 exit(-1);
17 }
18 client(readid,writeid);
19 msgctl(readid,IPC_RMID,NULL);
20 exit(0);
21 }
22
23 void client(int readid,int writeid)
24 {
25 size_t len;
26 ssize_t n;
27 char *ptr;
28 struct mymesg mesg;
29 printf("Send request to server.\n");
30 //set pid to message
31 snprintf(mesg.mesg_data,MSGMAX,"%d",readid);
32 len = strlen(mesg.mesg_data);
33 mesg.mesg_data[len] = ' '; //blank
34 ptr = mesg.mesg_data+len+1;
35 printf("Enter filename: ");
36 fgets(ptr,MSGMAX-len,stdin);
37 len = strlen(mesg.mesg_data);
38 if(mesg.mesg_data[len-1] == '\n')
39 len--;
40 mesg.mesg_len = len;
41 mesg.mesg_type = 1;
42 printf("mesg_data is :%s\n",mesg.mesg_data);
43 Mesg_send(writeid,&mesg);
44 printf("Send messge to server successed.\n");
45 //read from IPC,write to standard output
46 while( (n = Mesg_recv(readid,&mesg))>0)
47 {
48 write(STDOUT_FILENO,mesg.mesg_data,n);
49 putchar('\n');
50 }
51 if(n == 0 )
52 {
53 printf("Read file from server is completed.\n");
54 }
55 }
服务器程序如下:
1 #include "svmsg.h"
2
3 void server(int ,int);
4 void sig_child(int signo);
5
6 int main(int argc,char *argv[])
7 {
8 int msqid;
9 if((msqid = msgget(MQ_KEY,SVMSG_MODE | IPC_CREAT)) == -1)
10 {
11 perror("megget()");
12 exit(-1);
13 }
14 server(msqid,msqid);
15 exit(0);
16 }
17
18 void server(int readid,int writeid)
19 {
20 FILE *fp;
21 char *ptr;
22 pid_t pid;
23 ssize_t n;
24 ssize_t len;
25 struct mymesg mesg;
26 signal(SIGCHLD,sig_child);
27 printf("Waiting for client......\n");
28 for(; ;)
29 {
30 mesg.mesg_type = 1;
31 if((n = Mesg_recv(readid,&mesg)) == 0)
32 {
33 printf("pathname missing.\n");
34 continue;
35 }
36 mesg.mesg_data[n] = '\0';
37 printf("Received message from client is: %s\n",mesg.mesg_data);
38 if ((ptr = strchr(mesg.mesg_data,' ')) == NULL)
39 {
40 printf("bogus request: %s\n",mesg.mesg_data);
41 continue;
42 }
43 *ptr++ = 0;
44 writeid = atoi(mesg.mesg_data);
45 if(fork() == 0)
46 {
47 //open fiel and read data
48 if((fp = fopen(ptr,"r")) == NULL)
49 {
50 printf("open file failed.sent msg to client\n");
51 snprintf(mesg.mesg_data+n,sizeof(mesg.mesg_data)-n,": can't open,%s\n",strerror(errno));
52 mesg.mesg_len = strlen(ptr);
53 memmove(mesg.mesg_data,ptr,mesg.mesg_len);
54 Mesg_send(writeid,&mesg);
55 }
56 else
57 {
58 printf("open file successed.sent file to client\n");
59 while(fgets(mesg.mesg_data,MSGMAX,fp) != NULL)
60 {
61 mesg.mesg_len = strlen(mesg.mesg_data);
62 Mesg_send(writeid,&mesg);
63 }
64 fclose(fp);
65 }
66 printf("send compelted.\n");
67 mesg.mesg_len = 0;
68 Mesg_send(writeid,&mesg);
69 }
70 }
71 }
72
73 void sig_child(int signo)
74 {
75 pid_t pid;
76 int stat;
77 while ((pid = waitpid(-1,&stat,WNOHANG)) > 0);
78 return ;
79 }
程序测试结果如下:
System V 消息队列 - 复用消息的更多相关文章
- (二)RabbitMQ消息队列-RabbitMQ消息队列架构与基本概念
原文:(二)RabbitMQ消息队列-RabbitMQ消息队列架构与基本概念 没错我还是没有讲怎么安装和写一个HelloWord,不过快了,这一章我们先了解下RabbitMQ的基本概念. Rabbit ...
- 为什么使用消息队列?消息队列有什么优点和缺点?Kafka、ActiveMQ、RabbitMQ、RocketMQ 都有什么优点和缺点?
面试题 为什么使用消息队列? 消息队列有什么优点和缺点? Kafka.ActiveMQ.RabbitMQ.RocketMQ 都有什么区别,以及适合哪些场景? 面试官心理分析 其实面试官主要是想看看: ...
- 剖析nsq消息队列(四) 消息的负载处理
剖析nsq消息队列-目录 实际应用中,一部分服务集群可能会同时订阅同一个topic,并且处于同一个channel下.当nsqd有消息需要发送给订阅客户端去处理时,发给哪个客户端是需要考虑的,也就是我要 ...
- rabbitmq消息队列,消息发送失败,消息持久化,消费者处理失败相关
转:https://blog.csdn.net/u014373554/article/details/92686063 项目是使用springboot项目开发的,前是代码实现,后面有分析发送消息失败. ...
- activemq读取剩余消息队列中消息的数量
先上原文链接: http://blog.csdn.net/bodybo/article/details/5647968 ActiveMQ在C#中的应用 ActiveMQ是个好东东,不必多说.Acti ...
- 为什么使用消息队列? 消息队列有什么优点和缺点? Kafka、ActiveMQ、RabbitMQ、RocketMQ 都有什么区别,以及适合哪些场景?
https://blog.csdn.net/Iperishing/article/details/86674084
- Linux IPC System V 消息队列
模型 #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> ftok() //获取key ...
- 消息队列接口API(posix 接口和 system v接口)
消息队列 posix API 消息队列(也叫做报文队列)能够克服早期unix通信机制的一些缺点.信号这种通信方式更像\"即时\"的通信方式,它要求接受信号的进程在某个时间范围内对信 ...
- UNIX环境高级编程——system V消息队列
unix早期通信机制中的信号能够传送的信息量有限,管道则只能传送无格式字节流,这远远是不够的. 消息队列(也叫报文队列)客服了这些缺点: 消息队列就是一个消息的链表. 可以把消 ...
随机推荐
- 五个瓶颈影响你的Asp.Net程序(网站)性能
在今天的手机设备世界里,生活的节奏继续加快,因此访问你的网站的用户的耐心也在渐渐失去.同时,我提供了非常多的特性,为了防止你的网站变得过时或者廉价,你必须跟上竞争对手.你想赢得访问者的喝彩,但访问者没 ...
- jquery获取元素各种宽高及页面宽高总结
window.onload=function(){ var a = $("#div").width(),//width()返回元素的宽高,不包括padding/border/mar ...
- Android -- onWindowFocusChanged
Android中获取手机屏幕的高度和宽度,我们知道在onCreate方法中获取到的值都是为0的,有人说可以在onClick方法中获取值,这个也是个方法 ,但在onWindowFocusChanged方 ...
- 【架构】SpringCloud JHipster -微服务相关资料
SpringCloud-微服务相关资料 基于Spring Boot和Spring Cloud实现微服务架构学习(四)-Spring Cloud总结 - zeb_perfect的专栏 - 博客频道 - ...
- 如何判断CapsLock键是否按下
SHORT cap_state = ::GetKeyState(VK_CAPITAL); char str[10]; sprintf(str, "%d", ...
- 字段计算器VBS
ArcGIS属性表中右键可调用字段计算器.写一些简单代码可操作属性表,有VBS和Python两种. 现在要求是:如果"地块编码"为空,则将"地块编号"赋给&qu ...
- Python中参数多个值的表示法
今天在写Python脚本时,调用了数据管理-制图综合-融合工具,在ArcGIS里操作的参数设置如下: 如果融合字段只有一个那好办,如果融合字段有多个我该怎么表达,查看帮助文档中的示例代码明白了: 所以 ...
- STL - 容器 - Array
Array是C++ 11给STL新增加的容器 ArrayTest.cpp #include <array> #include <algorithm> #include < ...
- Android 逆向project 实践篇
Android逆向project 实践篇 上篇给大家介绍的是基础+小Demo实践. 假设没有看过的同学能够进去看看.(逆向project 初篇) 本篇主要给大家介绍怎样反编译后改动源代码, 并打包执行 ...
- 虚拟机stack全分析
通过jps -lv 获取到本地的一个JVM实例进程.再通过jstack pid > thread.txt ,把stack trace输出到thread.txt文件中. 2012-08-28 2 ...