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.采集传感器数据

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

//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">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <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");
           // v[0].value="hello";
           var xhr = new XMLHttpRequest;//创建对象
           var url="";
           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;">
    <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">
    <input type="button"  name="flash" onclick="get_info()">
     <br>
     <!-- type类型为radio表示单选框,
        表示同样类型的单选框name 必须相同 ,
    -->
    <h1>设备控制</h1>
    <br>
    LED灯
    on:<input type="radio" name="deng" id="ledon" checked="checked" onclick="set_status(id)">
    off:<input type="radio" name="deng" id="ledoff" onclick="set_status(id)">
    <br>
    蜂鸣器
    on:<input type="radio" name="qi" id="buzzeron" checked="checked" onclick="set_status(id)">
    off:<input type="radio" name="qi" id="buzzeroff" onclick="set_status(id)">

</body>

</html>

  • 31
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值