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

尘世一俗人653 2024-07-17 15:33:03 阅读 77

一、项目目标和框图

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

二、项目分析

1.服务器源码分析

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

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

三、核心功能代码

1.采集传感器数据

        modbus采集程序和webserver共同建立共享内存,modbus读取传感器得到的数据,将数据写入共享内存中;webserver将数据从共享内存中读出;

<code>//modbus采集传感器

void *handler_thread(void *arg)

{

key_t key;

int shmid;

struct msp *p;

//创建key值

key = ftok("1.txt", 'x');

if (key < 0)

{

perror("ftok err");

return NULL;

}

printf("key: %#x\n", key);

//创建或打开共享内存

shmid = shmget(key, 128, IPC_CREAT | IPC_EXCL | 0666); //没有则创建共享内存,已有则返回-1

if (shmid <= 0)

{

if (errno == EEXIST) //如果已存在则直接打开共享内存

shmid = shmget(key, 128, 0666); //直接打开共享内存,返回共享内存id

else

{

perror("shmget err");

return NULL;

}

}

printf("shmid: %d\n", shmid);

//映射共享内存到用户空间

p = (struct msp *)shmat(shmid, NULL, 0);

if (p == (struct msp *)-1)

{

perror("shmat err");

return NULL;

}

//操作共享内存

while (1)

{

printf("handler_thread\n");

// uint16_t dest[10] = {};

PACK *msg = arg;

modbus_read_registers(msg->ctx, 0, 4, p->dest);

printf("%d %d %d %d\n", p->dest[0], p->dest[1], p->dest[2], p->dest[3]);

//让从线程不退出,进程状态l也就是多线程

sleep(2);

}

return NULL;

}

//webserver服务器

static int handler_get(int sock, const char *input)

{

key_t key;

int shmid;

struct msp *p;

//创建key值

key = ftok("1.txt", 'x');

if (key < 0)

{

perror("ftok err");

return -1;

}

printf("key: %#x\n", key);

//创建或打开共享内存

shmid = shmget(key, 128, IPC_CREAT | IPC_EXCL | 0666); //没有则创建共享内存,已有则返回-1

if (shmid <= 0)

{

if (errno == EEXIST) //如果已存在则直接打开共享内存

shmid = shmget(key, 128, 0666); //直接打开共享内存,返回共享内存id

else

{

perror("shmget err");

return -1;

}

}

printf("shmid: %d\n", shmid);

//映射共享内存到用户空间

p = (struct msp *)shmat(shmid, NULL, 0);

if (p == (struct msp *)-1)

{

perror("shmat err");

return -1;

}

sscanf(input, "%d X%dY%dZ%d", p->dest[0], p->dest[1], p->dest[2], p->dest[3]);

printf("g:%d X:%dY:%dZ:%d\n", p->dest[0], p->dest[1], p->dest[2], p->dest[3]);

char reply_buf[HTML_SIZE] = {0};

printf("handler_get\n");

printf("%d %d%d%d\n", p->dest[0], p->dest[1], p->dest[2], p->dest[3]);

sprintf(reply_buf, "%d %d %d %d", p->dest[0], p->dest[1], p->dest[2], p->dest[3]);

printf("resp = %s\n", reply_buf);

send(sock, reply_buf, strlen(reply_buf), 0);

return 0;

}

 2.控制灯泡和蜂鸣器

       网页发出控制命令给webserver服务器控制灯和蜂鸣器的信息,webserver和modbus采集器用相同的条件建立两个程序间的消息队列,建立通信,将控制灯泡和蜂鸣器的信息传递给modbus采集器,modbus采集器用相关信息控制灯泡和蜂鸣器的开关

//modbus采集器

void *handler_thread2(void *arg)

{

key_t key;

int msgid;

key = ftok(".", 9);

if (key < 0)

{

perror("ftok err");

return NULL;

}

printf("key:%#x\n", key);

//打开消息队列

msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666);

if (msgid <= 0)

{

if (errno == EEXIST)

msgid = msgget(key, 0666);

else

{

perror("msgget err");

return NULL;

}

}

printf("msgid: %d\n", msgid);

//读取消息

struct msgbuf m;

while(1)

{

msgrcv(msgid, &m, sizeof(m) - sizeof(long), 10, 0); //20:表示读取消息的类型为20,0:代表阻塞,读取完消息才返回

printf("%d %d\n", m.num,m.num2);

PACK *msg = arg;

modbus_write_bit(msg->ctx2, m.num, m.num2);

// modbus_write_bit(msg->ctx2, 1, dest[1]);

}

// //让从线程不退出,进程状态l也就是多线程

return NULL;

}

//webserver服务器

static int handler_set(int sock, const char *input)

{

key_t key;

int msgid;

key = ftok(".", 9);

if (key < 0)

{

perror("ftok err");

return -1;

}

printf("key:%#x\n", key);

//打开消息队列

msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666);

if (msgid <= 0)

{

if (errno == EEXIST)

msgid = msgget(key, 0666);

else

{

perror("msgget err");

return -1;

}

}

printf("msgid: %d\n", msgid);

int number1,number2;

//input必须是"data1=1data2=6"类似的格式,注意前端过来的字符串会有双引号

sscanf(input, "set=%dset2=%d", &number1,&number2);

printf("num1 = %d,num2=%d\n", number1,number2);

char reply_buf[HTML_SIZE] = {0};

struct msgbuf mng;

mng.type = 10;

mng.num = number1;

mng.num2 =number2;

mng.ch = 'a';

msgsnd(msgid, &mng, sizeof(mng) - sizeof(long), 0); //0:阻塞,发完消息才返回

printf("num = %d num=%d\n", number1 ,number2);

sprintf(reply_buf, "set=%dset2=%d", number1,number2);

printf("resp = %s\n", reply_buf);

send(sock, reply_buf, strlen(reply_buf), 0);

return 0;

}

3.http网页显示和控制

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

<!DOCTYPE html>

<html lang="en">code>

<head>

<meta charset="UTF-8">code>

<meta name="viewport" content="width=device-width, initial-scale=1.0">code>

<meta http-equiv="X-UA-Compatible" content="ie=edge">code>

<title>信息采集</title>

<script>

function get_info()

{

var v = document.getElementsByName("username");

var xhr = new XMLHttpRequest();//创建对象

var url = "";

xhr.open("post", url, true);

xhr.onreadystatechange = function ()

{

if (xhr.readyState === 4 && xhr.status === 200)

{

console.log(xhr.responseText);

var str1 = xhr.responseText.split("", 2);

console.log(str1[0]);

console.log(str1[1]);

v[0].value = str1[0];

v[1].value = str1[1];

}

};

xhr.send("g:%#x X:%#xY:%#xZ:%#x");

}

function sendStatus(addr,status)

{

var xhr = new XMLHttpRequest();

var url = "";

xhr.open("post", url, true);

data = "set=" + addr + "set2=" + status;

console.log("req=" + data);

if (xhr.readyState === 4 && xhr.status === 200)

{

var str1 = xhr.responseTest;

console.log("resp=" + response);

};

xhr.send(data);

}

function set_status(obj)

{

if (obj == 'ledon')

{

sendStatus(0, 1);

}

else if (obj == 'ledoff')

{

sendStatus(0, 0);

}

else if (obj == 'buzzeron')

{

sendStatus(1, 1);

}

else if (obj == 'buzzeroff')

{

sendStatus(1, 0);

}

}

function get_info()

{

var v=document.getElementsByName("username");code>

// v[0].value="hello";code>

var xhr = new XMLHttpRequest;//创建对象

var url="";code>

xhr.open("post",url,ture);

xhr.onreadystatechange=function()

{

if(xhr.readyState==4&&xhr.status==200)

{

console.log(xhr.responseText);

v[0].value=xhr.responseText;

}

};

xhr.send("modbus_get");

}

</script>

</head>

<body>

<!--h1-h6是标题标签-->

<h1>what 阿尔 donging 呢?</h1>

yes,我吃饭嘞

<br>

<!--br表示换行-->

NO,我 dont eat

<div style="color:crimson;background:deepskyblue;">code>

<p>

<!--p段落标签-->

HTML(英文Hyper Text Markup Language的缩写)中文译为“超文本标记语言”。是用来描述网页的一种语言。

所谓超文本,因为它可以加入图片、声音、动画、多媒体等内容,不仅如此,它还可以从一个文件跳转到另一个文件,与世界各地主机的文件连接。

HTML 不是一种编程语言,而是一种标记语言 (markup language)

Web 浏览器的作用是读取 HTML 文档,并以网页的形式显示出它们。浏览器不会显示 HTML 标签,而是使用标签来解释页面的内容

</p>

</div>

用户名:

<!--input 表单标签,

type类型为特殊他表示文本输入框

value为默认值-->

<input type="test" name="username" value="lisi">code>

<input type="button" name="flash" onclick="get_info()">code>

<br>

<!-- type类型为radio表示单选框,

表示同样类型的单选框name 必须相同 ,

-->

<h1>设备控制</h1>

<br>

LED灯

on:<input type="radio" name="deng" id="ledon" checked="checked" onclick="set_status(id)">code>

off:<input type="radio" name="deng" id="ledoff" onclick="set_status(id)">code>

<br>

蜂鸣器

on:<input type="radio" name="qi" id="buzzeron" checked="checked" onclick="set_status(id)">code>

off:<input type="radio" name="qi" id="buzzeroff" onclick="set_status(id)">code>

</body>

</html>



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。