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

#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. Evaluate Reverse Polish Notation leetcode java

    题目: Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are + ...

  2. 请教如何改善C#中socket通信机客户端程序的健壮性

    我是做Socket的新手,最近做了一个Socket客户端程序,连接Server的时候,如果server存在,并且允许连接的话,程序无错,正常执行:但是如果Server不存在,或者拒绝连接,程序就会卡住 ...

  3. TJ Holowaychuk是怎样学习编程的?

    TJ Holowaychuk是怎样学习编程的? 学习了:https://blog.csdn.net/wozaixiaoximen/article/details/49507111 Q:TJ Holow ...

  4. OSX:不同OSX版本号的标记可能不兼容-续

    不同OSX版本号的标记可能不兼容-续: 经过測试,10.10DP2的Update.俗称DP3.的版本号也没有纠正这个问题.而造成该问题的是安装过程中一開始就选择中文,假设安装时使用英文.在第一次进入操 ...

  5. Python中的乱码

        我把写好的Python脚本导入到ArcGIS中的ToolBox中,在本机测试是没有问题的.为了把工具分享给其他人,即在其他电脑上使用,我必须将脚本文件(*.py)导入到工具箱文件(*.tbx) ...

  6. 配置Tomcat和JDK

    第一步:下载jdk和tomcat 第二步:安装和配置你的j2sdk和tomcat:执行j2sdk和tomcat的安装程序,然后按默认设置进行安装即可. 1.安装j2sdk以后,需要配置一下环境变量,在 ...

  7. 当Activity继承AppCompatActivity如何实现隐藏标题栏与状态栏

    @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); g ...

  8. TOMCAT问题总结

      迁移时间--2017年7月9日14:58:12Author:Marydon CreateTime--2016年12月25日21:55:09Author:MarydonTomcat问题总结问题一 A ...

  9. UsageGrideReport++

      迁移时间:2017年5月20日11:42:02CreateTime--2016年9月29日15:46:15Author:Marydon版本Gride Report++6.0使用说明:参考链接:ht ...

  10. scala中:: , +:, :+, :::, +++的区别

    4种操作符的区别和联系 一. ::   该方法被称为cons,意为构造,向队列的头部追加数据,创造新的列表. 用法为 x::list,其中x为加入到 头部的元素,无论x是列表与否,它都只将成为新生成列 ...