0


linux网络项目——基于WebServer的工业数据采集项目

一、项目目标和框图

项目目标:实现通过网页控制信息采集和通过网页控制灯泡和蜂鸣器的亮灭

二、项目分析

1.服务器源码分析

  1. 初始化服务器
  2. 循环等待连接,连接后创建线程,调用线程函数msg_request,在函数中调用handler_msg函数分析请求
  3. 在handler_msg函数中,先查看请求协议内容,其次获取请求方法、URL、参数,判断请求方法,对need_handler赋值,确定请求资源路径,如果请求地址没有携带任何资源,则默认返回index.html文件,如果资源不存在,返回404,如果需要处理(get带参数、post)调用handle_request函数,如果不需要(get请求不带参数且资源存在),调用echo_www函数,直接返回资源
  4. handle_request函数主要获取post数据,调用parse_and_process函数处理正文内容

2. 结合Modbus部分整体流程分析

三、核心功能代码

1.采集传感器数据

  1. modbus采集程序和webserver共同建立共享内存,modbus读取传感器得到的数据,将数据写入共享内存中;webserver将数据从共享内存中读出;
  1. //modbus采集传感器
  2. void *handler_thread(void *arg)
  3. {
  4. key_t key;
  5. int shmid;
  6. struct msp *p;
  7. //创建key值
  8. key = ftok("1.txt", 'x');
  9. if (key < 0)
  10. {
  11. perror("ftok err");
  12. return NULL;
  13. }
  14. printf("key: %#x\n", key);
  15. //创建或打开共享内存
  16. shmid = shmget(key, 128, IPC_CREAT | IPC_EXCL | 0666); //没有则创建共享内存,已有则返回-1
  17. if (shmid <= 0)
  18. {
  19. if (errno == EEXIST) //如果已存在则直接打开共享内存
  20. shmid = shmget(key, 128, 0666); //直接打开共享内存,返回共享内存id
  21. else
  22. {
  23. perror("shmget err");
  24. return NULL;
  25. }
  26. }
  27. printf("shmid: %d\n", shmid);
  28. //映射共享内存到用户空间
  29. p = (struct msp *)shmat(shmid, NULL, 0);
  30. if (p == (struct msp *)-1)
  31. {
  32. perror("shmat err");
  33. return NULL;
  34. }
  35. //操作共享内存
  36. while (1)
  37. {
  38. printf("handler_thread\n");
  39. // uint16_t dest[10] = {};
  40. PACK *msg = arg;
  41. modbus_read_registers(msg->ctx, 0, 4, p->dest);
  42. printf("%d %d %d %d\n", p->dest[0], p->dest[1], p->dest[2], p->dest[3]);
  43. //让从线程不退出,进程状态l也就是多线程
  44. sleep(2);
  45. }
  46. return NULL;
  47. }
  1. //webserver服务器
  2. static int handler_get(int sock, const char *input)
  3. {
  4. key_t key;
  5. int shmid;
  6. struct msp *p;
  7. //创建key值
  8. key = ftok("1.txt", 'x');
  9. if (key < 0)
  10. {
  11. perror("ftok err");
  12. return -1;
  13. }
  14. printf("key: %#x\n", key);
  15. //创建或打开共享内存
  16. shmid = shmget(key, 128, IPC_CREAT | IPC_EXCL | 0666); //没有则创建共享内存,已有则返回-1
  17. if (shmid <= 0)
  18. {
  19. if (errno == EEXIST) //如果已存在则直接打开共享内存
  20. shmid = shmget(key, 128, 0666); //直接打开共享内存,返回共享内存id
  21. else
  22. {
  23. perror("shmget err");
  24. return -1;
  25. }
  26. }
  27. printf("shmid: %d\n", shmid);
  28. //映射共享内存到用户空间
  29. p = (struct msp *)shmat(shmid, NULL, 0);
  30. if (p == (struct msp *)-1)
  31. {
  32. perror("shmat err");
  33. return -1;
  34. }
  35. sscanf(input, "%d X%dY%dZ%d", p->dest[0], p->dest[1], p->dest[2], p->dest[3]);
  36. printf("g:%d X:%dY:%dZ:%d\n", p->dest[0], p->dest[1], p->dest[2], p->dest[3]);
  37. char reply_buf[HTML_SIZE] = {0};
  38. printf("handler_get\n");
  39. printf("%d %d%d%d\n", p->dest[0], p->dest[1], p->dest[2], p->dest[3]);
  40. sprintf(reply_buf, "%d %d %d %d", p->dest[0], p->dest[1], p->dest[2], p->dest[3]);
  41. printf("resp = %s\n", reply_buf);
  42. send(sock, reply_buf, strlen(reply_buf), 0);
  43. return 0;
  44. }

2.控制灯泡和蜂鸣器

  1. 网页发出控制命令给webserver服务器控制灯和蜂鸣器的信息,webservermodbus采集器用相同的条件建立两个程序间的消息队列,建立通信,将控制灯泡和蜂鸣器的信息传递给modbus采集器,modbus采集器用相关信息控制灯泡和蜂鸣器的开关
  1. //modbus采集器
  2. void *handler_thread2(void *arg)
  3. {
  4. key_t key;
  5. int msgid;
  6. key = ftok(".", 9);
  7. if (key < 0)
  8. {
  9. perror("ftok err");
  10. return NULL;
  11. }
  12. printf("key:%#x\n", key);
  13. //打开消息队列
  14. msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666);
  15. if (msgid <= 0)
  16. {
  17. if (errno == EEXIST)
  18. msgid = msgget(key, 0666);
  19. else
  20. {
  21. perror("msgget err");
  22. return NULL;
  23. }
  24. }
  25. printf("msgid: %d\n", msgid);
  26. //读取消息
  27. struct msgbuf m;
  28. while(1)
  29. {
  30. msgrcv(msgid, &m, sizeof(m) - sizeof(long), 10, 0); //20:表示读取消息的类型为20,0:代表阻塞,读取完消息才返回
  31. printf("%d %d\n", m.num,m.num2);
  32. PACK *msg = arg;
  33. modbus_write_bit(msg->ctx2, m.num, m.num2);
  34. // modbus_write_bit(msg->ctx2, 1, dest[1]);
  35. }
  36. // //让从线程不退出,进程状态l也就是多线程
  37. return NULL;
  38. }
  1. //webserver服务器
  2. static int handler_set(int sock, const char *input)
  3. {
  4. key_t key;
  5. int msgid;
  6. key = ftok(".", 9);
  7. if (key < 0)
  8. {
  9. perror("ftok err");
  10. return -1;
  11. }
  12. printf("key:%#x\n", key);
  13. //打开消息队列
  14. msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666);
  15. if (msgid <= 0)
  16. {
  17. if (errno == EEXIST)
  18. msgid = msgget(key, 0666);
  19. else
  20. {
  21. perror("msgget err");
  22. return -1;
  23. }
  24. }
  25. printf("msgid: %d\n", msgid);
  26. int number1,number2;
  27. //input必须是"data1=1data2=6"类似的格式,注意前端过来的字符串会有双引号
  28. sscanf(input, "set=%dset2=%d", &number1,&number2);
  29. printf("num1 = %d,num2=%d\n", number1,number2);
  30. char reply_buf[HTML_SIZE] = {0};
  31. struct msgbuf mng;
  32. mng.type = 10;
  33. mng.num = number1;
  34. mng.num2 =number2;
  35. mng.ch = 'a';
  36. msgsnd(msgid, &mng, sizeof(mng) - sizeof(long), 0); //0:阻塞,发完消息才返回
  37. printf("num = %d num=%d\n", number1 ,number2);
  38. sprintf(reply_buf, "set=%dset2=%d", number1,number2);
  39. printf("resp = %s\n", reply_buf);
  40. send(sock, reply_buf, strlen(reply_buf), 0);
  41. return 0;
  42. }

3.http网页显示和控制

将虚拟机的IP地址在网页中打开,然后查询传感器得到的数据和控制灯泡和蜂鸣器

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>信息采集</title>
  8. <script>
  9. function get_info()
  10. {
  11. var v = document.getElementsByName("username");
  12. var xhr = new XMLHttpRequest();//创建对象
  13. var url = "";
  14. xhr.open("post", url, true);
  15. xhr.onreadystatechange = function ()
  16. {
  17. if (xhr.readyState === 4 && xhr.status === 200)
  18. {
  19. console.log(xhr.responseText);
  20. var str1 = xhr.responseText.split("", 2);
  21. console.log(str1[0]);
  22. console.log(str1[1]);
  23. v[0].value = str1[0];
  24. v[1].value = str1[1];
  25. }
  26. };
  27. xhr.send("g:%#x X:%#xY:%#xZ:%#x");
  28. }
  29. function sendStatus(addr,status)
  30. {
  31. var xhr = new XMLHttpRequest();
  32. var url = "";
  33. xhr.open("post", url, true);
  34. data = "set=" + addr + "set2=" + status;
  35. console.log("req=" + data);
  36. if (xhr.readyState === 4 && xhr.status === 200)
  37. {
  38. var str1 = xhr.responseTest;
  39. console.log("resp=" + response);
  40. };
  41. xhr.send(data);
  42. }
  43. function set_status(obj)
  44. {
  45. if (obj == 'ledon')
  46. {
  47. sendStatus(0, 1);
  48. }
  49. else if (obj == 'ledoff')
  50. {
  51. sendStatus(0, 0);
  52. }
  53. else if (obj == 'buzzeron')
  54. {
  55. sendStatus(1, 1);
  56. }
  57. else if (obj == 'buzzeroff')
  58. {
  59. sendStatus(1, 0);
  60. }
  61. }
  62. function get_info()
  63. {
  64. var v=document.getElementsByName("username");
  65. // v[0].value="hello";
  66. var xhr = new XMLHttpRequest;//创建对象
  67. var url="";
  68. xhr.open("post",url,ture);
  69. xhr.onreadystatechange=function()
  70. {
  71. if(xhr.readyState==4&&xhr.status==200)
  72. {
  73. console.log(xhr.responseText);
  74. v[0].value=xhr.responseText;
  75. }
  76. };
  77. xhr.send("modbus_get");
  78. }
  79. </script>
  80. </head>
  81. <body>
  82. <!--h1-h6是标题标签-->
  83. <h1>what 阿尔 donging 呢?</h1>
  84. yes,我吃饭嘞
  85. <br>
  86. <!--br表示换行-->
  87. NO,我 dont eat
  88. <div style="color:crimson;background:deepskyblue;">
  89. <p>
  90. <!--p段落标签-->
  91. HTML(英文Hyper Text Markup Language的缩写)中文译为“超文本标记语言”。是用来描述网页的一种语言。
  92. 所谓超文本,因为它可以加入图片、声音、动画、多媒体等内容,不仅如此,它还可以从一个文件跳转到另一个文件,与世界各地主机的文件连接。
  93. HTML 不是一种编程语言,而是一种标记语言 (markup language)
  94. Web 浏览器的作用是读取 HTML 文档,并以网页的形式显示出它们。浏览器不会显示 HTML 标签,而是使用标签来解释页面的内容
  95. </p>
  96. </div>
  97. 用户名:
  98. <!--input 表单标签,
  99. type类型为特殊他表示文本输入框
  100. value为默认值-->
  101. <input type="test" name="username" value="lisi">
  102. <input type="button" name="flash" onclick="get_info()">
  103. <br>
  104. <!-- type类型为radio表示单选框,
  105. 表示同样类型的单选框name 必须相同 ,
  106. -->
  107. <h1>设备控制</h1>
  108. <br>
  109. LED灯
  110. on:<input type="radio" name="deng" id="ledon" checked="checked" onclick="set_status(id)">
  111. off:<input type="radio" name="deng" id="ledoff" onclick="set_status(id)">
  112. <br>
  113. 蜂鸣器
  114. on:<input type="radio" name="qi" id="buzzeron" checked="checked" onclick="set_status(id)">
  115. off:<input type="radio" name="qi" id="buzzeroff" onclick="set_status(id)">
  116. </body>
  117. </html>

本文转载自: https://blog.csdn.net/qq_68683005/article/details/139056450
版权归原作者 尘世一俗人653 所有, 如有侵权,请联系我们删除。

“linux网络项目——基于WebServer的工业数据采集项目”的评论:

还没有评论