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

#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 消息队列 - 复用消息的更多相关文章

  1. (二)RabbitMQ消息队列-RabbitMQ消息队列架构与基本概念

    原文:(二)RabbitMQ消息队列-RabbitMQ消息队列架构与基本概念 没错我还是没有讲怎么安装和写一个HelloWord,不过快了,这一章我们先了解下RabbitMQ的基本概念. Rabbit ...

  2. 为什么使用消息队列?消息队列有什么优点和缺点?Kafka、ActiveMQ、RabbitMQ、RocketMQ 都有什么优点和缺点?

    面试题 为什么使用消息队列? 消息队列有什么优点和缺点? Kafka.ActiveMQ.RabbitMQ.RocketMQ 都有什么区别,以及适合哪些场景? 面试官心理分析 其实面试官主要是想看看: ...

  3. 剖析nsq消息队列(四) 消息的负载处理

    剖析nsq消息队列-目录 实际应用中,一部分服务集群可能会同时订阅同一个topic,并且处于同一个channel下.当nsqd有消息需要发送给订阅客户端去处理时,发给哪个客户端是需要考虑的,也就是我要 ...

  4. rabbitmq消息队列,消息发送失败,消息持久化,消费者处理失败相关

    转:https://blog.csdn.net/u014373554/article/details/92686063 项目是使用springboot项目开发的,前是代码实现,后面有分析发送消息失败. ...

  5. activemq读取剩余消息队列中消息的数量

    先上原文链接: http://blog.csdn.net/bodybo/article/details/5647968  ActiveMQ在C#中的应用 ActiveMQ是个好东东,不必多说.Acti ...

  6. 为什么使用消息队列? 消息队列有什么优点和缺点? Kafka、ActiveMQ、RabbitMQ、RocketMQ 都有什么区别,以及适合哪些场景?

    https://blog.csdn.net/Iperishing/article/details/86674084

  7. Linux IPC System V 消息队列

    模型 #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> ftok() //获取key ...

  8. 消息队列接口API(posix 接口和 system v接口)

    消息队列 posix API 消息队列(也叫做报文队列)能够克服早期unix通信机制的一些缺点.信号这种通信方式更像\"即时\"的通信方式,它要求接受信号的进程在某个时间范围内对信 ...

  9. UNIX环境高级编程——system V消息队列

    unix早期通信机制中的信号能够传送的信息量有限,管道则只能传送无格式字节流,这远远是不够的.     消息队列(也叫报文队列)客服了这些缺点:     消息队列就是一个消息的链表.     可以把消 ...

随机推荐

  1. 配置sonarqube+maven

    Maven与Sonar配合使用  准备工作:下载sonarqube源码即可  步骤:      1).安装sonar 解压,启动sonarqube-4.1\bin\windows-x86-32目录下的 ...

  2. 查询分页-----强势top

    查询分页:语句1性能提升10倍多,仅仅是由于多了个topkeyword,非常不理解啊!!!! 1.查询时间1s内,r_object_id主键 select top 100 * from (  sele ...

  3. myeclipse查询mysql出来的汉字是乱码

    乱码肯定是编码和解码方式不一致产生的! 1: 在mysql 中输入 status 可看到db 编码是什么         可选utf-8 or gbk 2:  连接时jdbc:mysql://serv ...

  4. 防盗链Nginx设置图片防盗链,设置无效的请仔细看红字

    *******************************************************************切记,替换的图片地址要使用没有防盗链的网站图片,否则由于替换的图片 ...

  5. 【树莓派】制作树莓派所使用的img镜像(二)

    树莓派制作的镜像,需要如何使用,这里直接引用目前树莓派官方的文章,不再重复描述: 参考:http://shumeipai.nxez.com/2013/08/31/usb-image-tool.html ...

  6. serialport控件的详细用法

    http://www.cnblogs.com/jerry-bian/archive/2012/01/10/2317861.html 最近在做通讯协议,关于SerialPort类 DataReceive ...

  7. centos下两种方法安装git

    来自:http://blog.slogra.com/post-176.html 今天下个包需要使用git,网上找了下看到大多数只有编译安装,并且编译安装还有错,不知道他们也没有实验过,这里我来给大家介 ...

  8. $stateParams 详解

     如何传递参数(参考 http://www.cnblogs.com/jager/p/5293225.html) 首先,要在目标页面定义接受的参数: 传参, ui-sref: $state.go: 接收 ...

  9. 机器学习笔记(十)EM算法及实践(以混合高斯模型(GMM)为例来次完整的EM)

    今天要来讨论的是EM算法.第一眼看到EM我就想到了我大枫哥,EM Master,千里马.RUA!!!不知道看这个博客的人有没有懂这个梗的. 好的,言归正传.今天要讲的EM算法,全称是Expectati ...

  10. google kaptcha 验证码组件使用简介

    kaptcha 是一个非常实用的验证码生成工具.有了它,你可以生成各种样式的验证码,因为它是可配置的.kaptcha工作的原理是调用 com.google.code.kaptcha.servlet.K ...