一、数据刷新

在主框架中可以看到数据刷新线程:pthread_refrash.c

略去出错处理,如下:

1 #include "data_global.h"
 2 #include "sem.h"
 3 
 4 #define N 1024  //for share memory
 5 
 6 //外部声明键值与id
 7 extern int shmid;
 8 extern int msgid;
 9 extern int semid;
10 
11 extern key_t shm_key;
12 extern key_t sem_key;
13 extern key_t key; //msg_key
14 
15 //外部互斥体声明
16 extern pthread_mutex_t mutex_client_request,
17                 mutex_refresh,
18                 ...
19 //外部声明条件变量
20 extern pthread_cond_t  cond_client_request,
21                 cond_refresh,
22                 ...
23 
24 //包含所有环境信息的结构体,在data_global.h中声明,
25 //最终为makeru_zigbee_info与makeru_a9_info这两个结构体的组合
26 extern struct env_info_client_addr  sm_all_env_info;
27 
28 //将所有环境信息结构体与home_id再次封装成一个结构体
29  struct shm_addr
30  {
31     char shm_status;   //shm_status可以等于home_id,用来区分共享内存数据
32     struct env_info_client_addr  sm_all_env_info;
33 };
34 struct shm_addr *shm_buf;
35 
36 //模拟数据刷新的函数
37 int file_env_info_struct(struct env_info_client_addr  *rt_status,int home_id);
38 
39 /* shm复习:
40  * 共享内存使用步骤:
41  *    1 创建/打开共享内存 —— shmget
42  *    2 映射共享内存,即把指定的共享内存映射到进程地址空间用于访问 —— shmat
43  *    3 读写共享内存 —— 地址 = shmat
44  *    4 撤销共享内存映射 —— shmdt
45  *    5 删除共享内存对象 —— shmctl
46 */
47 
48 void *pthread_refresh(void *arg)
49 {
50     //semaphore for access to resource limits
51     //信号量+共享内存实现对资源的互斥操作
52     
53     //"/tmp"--路径,'i'--生成key的数字,范围1-255 ,返回值:key_t
54     sem_key = ftok("/tmp",'i');
55 
56     //创建信号量,返回id
57     semid = semget(sem_key,1,IPC_CREAT|IPC_EXCL|0666);
58     
59     init_sem (semid, 0, 1);
60     
61 
62     //创建共享内存
63     shm_key = ftok("/tmp",'i');
64     shmid = shmget(shm_key,N,IPC_CREAT|IPC_EXCL|0666);
65 
66     //映射共享内存,为shm_buf指定共享内存
67     shm_buf = (struct shm_addr *)shmat(shmid,NULL,0));
68 
69     //清空一下shm_buf
70     bzero (shm_buf, sizeof (struct shm_addr));
71     //
72     while(1){
73         sem_p(semid,0);  //P操作
74         shm_buf->shm_status = 1;  //指定home1
75         file_env_info_struct(&shm_buf->sm_all_env_info,shm_buf->shm_status);  //刷新数据到web
76         sleep(1);
77         sem_v(semid,0);  //V操作
78     }
79     
80     
81 int file_env_info_struct(struct env_info_client_addr *rt_status,int home_id)
82 {
83     int  env_info_size = sizeof(struct env_info_client_addr);
84     printf("env_info_size = %d.\n",env_info_size);
85 
86     rt_status->monitor_no[home_id].zigbee_info.temperature = 10.0;
87         ...
88     rt_status->monitor_no[home_id].zigbee_info.reserved[1]  = -0.01;
89 
90     rt_status->monitor_no[home_id].a9_info.adc  = 9.0;
91     ...
92     rt_status->monitor_no[home_id].a9_info.reserved[1]  = -0.01;
93     
94     return 0;
95 }

 

2、在CGI部分

env1.c -- > env1.cgi

1 #include <stdio.h>
 2 ...
 3 #include "cgic.h"
 4 #include "data_global.h"
 5 
 6 
 7 //包含环境信息的结构体
 8 struct shm_addr
 9 {
10     char shm_status;
11     struct env_info_client_addr  sm_all_env_info;
12 };
13 
14 int cgiMain()
15 {
16     key_t key;
17     int shmid,semid;
18     struct shm_addr *shm_buf;
19 
20     //key就相当于文件名,/tmp为其路径
21     key = ftok("/tmp",'i');
22     
23     //创建信号量
24     semid  = semget(key, 1, 0666);
25     
26     //映射shm,并让shm_buf指向shm
27     shm_buf = (struct shm_addr*)shmat(shmid, NULL, 0);
28 
29     //信号量:P操作
30     sem_p(semid,0);
31 
32     //CGI接口规范
33     //CGI即通用网关接口,就是处理HTML网页端数据与服务器端的接口
34     //使服务器和网页端能互相识别处理彼此的数据
35     if (shm_buf->shm_status == 1)
36     {
37         //最终会在网页端打印以下信息
38         fprintf(cgiOut, "<h4>Temperature:\t%0.2f</H4>\n ", shm_buf->sm_all_env_info.monitor_no[shm_buf->shm_status].zigbee_info.temperature );
39         ...
40         fprintf(cgiOut, "<h4>A9数据显示部分</H4>\n ");
41         fprintf(cgiOut, "<h4>Adc:\t%0.2f</H4>\n ", shm_buf->sm_all_env_info.monitor_no[shm_buf->shm_status].a9_info.adc);
42         ...
43         fprintf(cgiOut, "<h4>A9-RESERVED[1]:\t%d</H4>\n ", shm_buf->sm_all_env_info.monitor_no[shm_buf->shm_status].a9_info.reserved[1]);
44 
45         fprintf(cgiOut, "<h4>......</H4>\n ");
46     }
47     else
48     {
49     }
50     //信号量:V操作
51     sem_v (semid, 0);
52     return 0;
53 }

 

3、网页端

env1.html

1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 2 <html xmlns="http://www.w3.org/1999/xhtml">
 3 
 4     <head>
 5         <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 6         <title>仓库一环境信息</title>
 7     </head>
 8 
 9     <body>
10 
11         <body background="./images/huaqing002.jpg">
12             </div>
13             <table width="1080" border="0" height="200" background="./images/huaqing2.jpg" align="center">
14                 <tr>
15                     <td> </td>
16                     <td> </td>
17                 </tr>
18             </table>
19             <table width="1080" border="1" align="center">
20                 <tr>
21                     <td width="556">
22                         <div align="center">
23                             <h3>环境信息</h3></div>
24                     </td>
25                     <td width="500">
26                         <div align="center">
27                             <a href="home1.html">
28                                 <h3>回主页</h3></a>
29                         </div>
30                     </td>
31                 </tr>
32             </table>
33             <table width="1080" height="511" border="1" align="center">
34                 <tr>
35                     <td width="283" height="500" background="./images/zigee.jpg" align="left"></td>
36                     <td width="432"><iframe src="cgi-bin/env1.cgi" height="500" width="518" align="middle"></iframe></td>
37                     <td width="283" background="./images/gprs.jpg" align="right"></td>
38                 </tr>
39             </table>
40         </body>
41 
42 </html>

在第36行,网页端会调用到服务器端的cgi-bin目录下的env1.cgi文件进行数据的刷新与显示,

效果如下:

windows监控应用上下行流量原理 监控需要上行还是下行_共享内存

 

 

 服务器端下的目录结构:

windows监控应用上下行流量原理 监控需要上行还是下行_共享内存_02

 

 

二、web端命令下发

从上往下分析

windows监控应用上下行流量原理 监控需要上行还是下行_html_03

 

   在html端通过action,将对应的控制指令交给xxxx.cgi,在CGI进程中,对数据进行解析,将数据填充进消息,在将消息发送给消息队列,

 给主线程中的接收用户请求线程,获取消息队列里的消息,进而将指令分发给不同的主线程。

以led为例:

在网页查看控制部分的源码:

1 <table width="400" height="270" align="center" border="3" bordercolor="red">
 2             <td height="60">
 3                 <div align="center">
 4                     <form id="form1" name="form1" method="post" action="cgi-bin/a9_led.cgi">
 5                         <div class="strip1">
 6                             <input type="hidden" name="store" id="hiddenField" value="1" /> Led:
 7                             <label>
 8                 <input type="radio" name="led" value="1" id="led_0" />
 9                 on</label>
10 
11                             <label>
12                 <input type="radio" name="led" value="0" id="led_1" />
13                 off</label>
14                             <input type="submit" name="button" id="button" value="确定" />
15                         </div>
16                     </form>
17                 </div>
18             </td>
19             </tr>
20             <tr>

由4四行,去查看a9_led.c

1 #include <stdio.h> 
 2 #include "cgic.h" 
 3     ...    
 4 #include <sys/msg.h>
 5 
 6 #define N 8
 7 
 8 struct msg
 9 {
10     long type;
11     long msgtype;
12     unsigned char text[N];
13 };
14 
15 
16 int cgiMain() 
17 { 
18     key_t key;
19     char buf[N];
20     char sto_no[2];
21     int msgid;
22     struct msg msg_buf;
23     memset(&msg_buf,0,sizeof(msg_buf));
24     
25     cgiFormString("led",buf,N);
26     cgiFormString("store",sto_no,2);
27 
28     key = ftok("/tmp", 'g');
29 
30     msgid = msgget(key, 0666);
31 
32     bzero (msg_buf.text, sizeof (msg_buf.text));
33 
34     if (buf[0] == '1')
35     {    //构造命令,并填充结构体
36         msg_buf.text[0] = ((sto_no[0] - 48)) << 6 | (0x0 << 4) | (1 << 0);
37     }
38     else
39     {
40         msg_buf.text[0] = ((sto_no[0] - 48)) << 6 | (0x0 << 4) | (0 << 0);
41     }
42     
43     //填充结构体
44     msg_buf.type = 1L;
45     msg_buf.msgtype = 1L;  //具体的消息类型 === 指代控制的设备,如1L->LED
46     msgsnd(msgid, &msg_buf,sizeof(msg_buf)-sizeof(long),0);
47 
48     sto_no[0] -= 48;
49 
50     cgiHeaderContentType("text/html\n\n"); 
51     fprintf(cgiOut, "<HTML><HEAD>\n"); 
52     fprintf(cgiOut, "<TITLE>My CGI</TITLE></HEAD>\n"); 
53     fprintf(cgiOut, "<BODY>"); 
54 
55     fprintf(cgiOut, "<H2>send sucess</H2>");
56 
57     //fprintf(cgiOut, "<a href='.html'>返回</a>"); 
58     fprintf(cgiOut, "<meta http-equiv=\"refresh\" content=\"1;url=../a9_zigbee%d.html\">", sto_no[0]);
59     fprintf(cgiOut, "</BODY>\n"); 
60     fprintf(cgiOut, "</HTML>\n"); 
61 
62     return 0; 
63 }

 

在A9主线程中的接收用户请求线程获取消息队列中的消息,进而判断并分发给不同子线程

1 #include "data_global.h"
 2 
 3 extern int msgid;
 4 extern key_t key;
 5 
 6 extern pthread_mutex_t mutex_client_request,
 7                 mutex_refresh,
 8                 ...
 9                  mutex_led,
10 
11 extern pthread_cond_t  cond_client_request,
12                 cond_refresh,
13                 ...
14                  cond_led;
15 
16 
17 struct msg msgbuf;
18 
19 
20 void *pthread_client_request(void *arg)
21 {
22     key = ftok("/tmp",'g')) < 0);
23 
24     msgid = msgget(key,IPC_CREAT|IPC_EXCL|0666);
25 
26     while(1){
27         bzero(&msgbuf,sizeof(msgbuf));
28             printf("wait form client request...\n");
29         //从消息队列接收消息
30         msgrcv (msgid, &msgbuf, sizeof (msgbuf) - sizeof (long), 1L, 0);
31         printf ("Get %ldL msg\n", msgbuf.msgtype);
32         printf ("text[0] = %#x\n", msgbuf.text[0]);
33         
34         //对消息进行判断进而去调用不同的线程处理
35         switch(msgbuf.msgtype){
36             case 1L:
37                     printf("hello led\n");
38                 break;
39             case 2L:
40                     printf("hello beep\n");
41                 break;
42             case 3L:
43                     printf("hello seg\n");
44                 break;
45             case 4L:
46                     printf("hello fan\n");
47                 break;
48             case 5L:
49                     printf("set env data\n");
50                     printf("temMAX: %d\n",*((int *)&msgbuf.text[1]));
51                     ...
52                     printf("illMAX: %d\n",*((int *)&msgbuf.text[21]));
53 
54                 break;
55             case ...
56             case 10L:
57             default:
58                 break;
59                 
60         }
61     }
62 
63 }
64 
65 #if 0
66 
67         long msgtype;//具体的消息类型
68         消息类型的分配:
69             1L:         LED控制
70             2L:            蜂鸣器控制
71             3L:            四路LED灯模拟的数码管
72             4L:            风扇
73             5L:            温湿度最值设置
74             6L-7L-8L-9L,用于个人的扩展
75             10L:         3G通信模块-GPRS 
76         switch(msgbuf.msgtype){
77             case 1L: ...  break;
78             ....
79             default ....  break;
80         }
81 #endif

 

测试结果:

windows监控应用上下行流量原理 监控需要上行还是下行_windows监控应用上下行流量原理_04

        

windows监控应用上下行流量原理 监控需要上行还是下行_windows监控应用上下行流量原理_05