首页 > 其他分享 >基于WebServer的工业数据采集系统

基于WebServer的工业数据采集系统

时间:2024-09-25 17:22:58浏览次数:9  
标签:基于 return int 采集 WebServer key printf input include

 一、项目框架及流程

二、http简介

HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于Web Browser(浏览器)到Web Server(服务器)进行数据交互的传输协议。

HTTP是应用层协议

HTTP是一个基于TCP通信协议传输来传递数据(HTML 文件, 图片文件, 查询结果等)

HTTP协议工作于B/S架构上,浏览器作为HTTP客户端通过URL主动向HTTP服务端即WEB服务器发送所有请求,Web服务器根据接收到的请求后,向客户端发送响应信息。

HTTP默认端口号为80,但是你也可以改为8080或者其他端口

三、http特点

HTTP是短连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

HTTP是媒体独立的:这意味着,只要客户端和服务器知道如何处理的数据内容,任何类型的数据都可以通过HTTP发送。客户端以及服务器指定使用适合的MIME-type内容类型。

HTTP是无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

四、代码实现

   采用多线程模式,一个线程用来循环读取传感器数据,一个线程用来发送控制命令。

//数据采集代码

#include <modbus.h>
#include <modbus-tcp.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/msg.h>
#include <errno.h>

modbus_t *ctx;
struct msgbuf
{
    long type; // 必须有,在第一个,表示消息的类型,值>0!
    int num1;  // 消息正文,自己定义
    int num2;
};

void *handler(void *arg);

int main(int argc, char const *argv[])
{
    int shmid;
    key_t key;
    uint16_t *p;
    key = ftok("00.c", 'a');
    if (key < 0)
    {
        perror("key err");
        return -1;
    }
    printf("key: %#x\n", key);

    // 打开或创建共享内存
    shmid = shmget(key, 128, IPC_CREAT | IPC_EXCL | 0777); // 如果共享内存不存在则创建,存在则返回-1
    if (shmid <= 0)
    {
        if (errno == EEXIST)                // 如果共享内存已存在则,直接打开
            shmid = shmget(key, 128, 0777); // 直接打开已有的共享内存并且获得共享内存id
        else
        {
            perror("shmget err");
            return -1;
        }
    }
    printf("shmid: %d\n", shmid);

    // 映射共享内存
    p = (uint16_t *)shmat(shmid, NULL, 0);
    if (p == (uint16_t *)-1)
    {
        perror("shmat err");
        return -1;
    }

    // 1.创建实例
    ctx = modbus_new_tcp(argv[1], 502);
    // 3.设置从机id(主从线程)
    modbus_set_slave(ctx, 0x01);
    // 4.创建连接(主从线程)
    modbus_connect(ctx);
    // 2.创建新线程
    pthread_t tid;
    pthread_create(&tid, NULL, handler, NULL);
    // 5.主线程:04功能码读输入寄存器循环
    uint16_t dest[32] = {0};
    while (1)
    {
        modbus_read_input_registers(ctx, 0x00, 2, p);
        printf("temp:%02x\nhumi:%02x\n", p[0], p[1]);
        sleep(1);
    }
    pthread_join(tid, NULL);
    modbus_free(ctx);
    modbus_close(ctx);
    // 取消映射
    shmdt(p);

    // 删除共享内存
    shmctl(shmid, IPC_RMID, NULL);
    return 0;
}
// 6.从线程:05功能码写单个线圈
void *handler(void *arg)
{
    int a, b;
    while (1)
    {
        key_t key;
        int msgid;

        if ((key = ftok("00.c", 'a')) < 0)
        {
            perror("ftok err");
        }
        printf("key: %#x\n", key);

        // 打开或创建消息队列
        msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0777);
        if (msgid <= 0)
        {
            if (errno == EEXIST)
                msgid = msgget(key, 0777); // 如果已经存在消息队列那直接打开该消息队列
            else
            {
                perror("msgget err");
            }
        }
        printf("msgid: %d\n", msgid);
        struct msgbuf m;
        msgrcv(msgid, &m, sizeof(m) - sizeof(long), 20, 0); // 0:阻塞,读完消息再返回
        modbus_write_bit(ctx, m.num1, m.num2);
    }
    pthread_exit(NULL);
}
 

//服务代码

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <modbus.h>
#include <modbus-tcp.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <sys/shm.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/msg.h>
#include <errno.h>
#include "custom_handle.h"

#define KB 1024
#define HTML_SIZE (64 * KB)
struct msgbuf
{
    long type; // 必须有,在第一个,表示消息的类型,值>0!
    int num1;  // 消息正文,自己定义
    int num2;
};

// 普通的文本回复需要增加html头部
#define HTML_HEAD "Content-Type: text/html\r\n" \
                  "Connection: close\r\n"

static int handle_login(int sock, const char *input)
{
    char reply_buf[HTML_SIZE] = {0};
    char *uname = strstr(input, "username=");
    uname += strlen("username=");
    char *p = strstr(input, "password");
    *(p - 1) = '\0';
    printf("username = %s\n", uname);

    char *passwd = p + strlen("password=");
    printf("passwd = %s\n", passwd);

    if (strcmp(uname, "admin") == 0 && strcmp(passwd, "admin") == 0)
    {
        sprintf(reply_buf, "<script>localStorage.setItem('usr_user_name', '%s');</script>", uname);
        strcat(reply_buf, "<script>window.location.href = '/index.html';</script>");
        send(sock, reply_buf, strlen(reply_buf), 0);
    }
    else
    {
        printf("web login failed\n");

        //"用户名或密码错误"提示,chrome浏览器直接输送utf-8字符流乱码,没有找到太好解决方案,先过渡
        char out[128] = {0xd3, 0xc3, 0xbb, 0xa7, 0xc3, 0xfb, 0xbb, 0xf2, 0xc3, 0xdc, 0xc2, 0xeb, 0xb4, 0xed, 0xce, 0xf3};
        sprintf(reply_buf, "<script charset='gb2312'>alert('%s');</script>", out);
        strcat(reply_buf, "<script>window.location.href = '/login.html';</script>");
        send(sock, reply_buf, strlen(reply_buf), 0);
    }

    return 0;
}

static int handle_add(int sock, const char
                                    *input)
{
    int number1, number2;

    // input必须是"data1=1data2=6"类似的格式,注意前端过来的字符串会有双引号
    sscanf(input, "data1=%ddata2=%d", &number1, &number2);
    printf("num1 = %d\n", number1);

    char reply_buf[HTML_SIZE] = {0};
    printf("num = %d\n", number1 + number2);
    sprintf(reply_buf, "%d", number1 + number2);
    printf("resp = %s\n", reply_buf);
    send(sock, reply_buf, strlen(reply_buf), 0);

    return 0;
}

static int handle_collect(int sock, const char *input)
{
    int shmid;
    key_t key;
    uint16_t *p;
    key = ftok("00.c", 'a');
    if (key < 0)
    {
        perror("key err");
        return -1;
    }
    printf("key: %#x\n", key);

    // 打开或创建共享内存
    shmid = shmget(key, 128, IPC_CREAT | IPC_EXCL | 0777); // 如果共享内存不存在则创建,存在则返回-1
    if (shmid <= 0)
    {
        if (errno == EEXIST)                // 如果共享内存已存在则,直接打开
            shmid = shmget(key, 128, 0777); // 直接打开已有的共享内存并且获得共享内存id
        else
        {
            perror("shmget err");
            return -1;
        }
    }
    printf("shmid: %d\n", shmid);

    // 映射共享内存
    p = (uint16_t *)shmat(shmid, NULL, 0);
    if (p == (uint16_t *)-1)
    {
        perror("shmat err");
        return -1;
    }

    char reply_buf[HTML_SIZE];
    printf("temp:%02x\nhumi:%02x\n", p[0], p[1]);
    sprintf(reply_buf, "温度:%d 湿度:%d", p[0], p[1]);
    printf("%s\n", reply_buf);
    send(sock, reply_buf, strlen(reply_buf), 0);
    return -1;
}

static int handle_set(int sock, const char *input)
{
    key_t key;
    int msgid;

    if ((key = ftok("00.c", 'a')) < 0)
    {
        perror("ftok err");
        return -1;
    }
    printf("key: %#x\n", key);

    // 打开或创建消息队列
    msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0777);
    if (msgid <= 0)
    {
        if (errno == EEXIST)
            msgid = msgget(key, 0777); // 如果已经存在消息队列那直接打开该消息队列
        else
        {
            perror("msgget err");
            return -1;
        }
    }
    printf("msgid: %d\n", msgid);

    int number1, number2;

    // input必须是"data1=1data2=6"类似的格式,注意前端过来的字符串会有双引号
    sscanf(input, "set %d %d", &number1, &number2);
    printf("num1 = %d\n", number1);
    printf("num2 = %d\n", number2);

    // 添加消息
    struct msgbuf msg;
    msg.type = 20;
    msg.num1 = number1;
    msg.num2 = number2;
    msgsnd(msgid, &msg, sizeof(msg) - sizeof(long), 0); // 0:发完消息再返回,而不是立即返回函数
    return -1;
}

/**
 * @brief 处理自定义请求,在这里添加进程通信
 * @param input
 * @return
 */
int parse_and_process(int sock, const char *query_string, const char *input)
{
    // query_string不一定能用的到

    // 先处理登录操作
    if (strstr(input, "username=") && strstr(input, "password="))
    {
        return handle_login(sock, input);
    }
    // 处理求和请求
    else if (strstr(input, "data1=") && strstr(input, "data2="))
    {
        return handle_add(sock, input);
    }
    else if (strstr(input, "get"))
    {
        return handle_collect(sock, input);
    }
    else if (strstr(input, "set"))
    {
        return handle_set(sock, input);
    }

    else // 剩下的都是json请求,这个和协议有关了
    {
        // 构建要回复的JSON数据
        const char *json_response = "{\"message\": \"Hello, client!\"}";

        // 发送HTTP响应给客户端
        send(sock, json_response, strlen(json_response), 0);
    }

    return 0;
}

//.h文件


#ifndef CUSTOM_HANDLE_H
#define CUSTOM_HANDLE_H

#include <stdio.h>
#include <string.h>

int parse_and_process(int sock, const char *query_string, const char *input);

#endif  // CUSTOM_HANDLE_H
 

标签:基于,return,int,采集,WebServer,key,printf,input,include
From: https://blog.csdn.net/weixin_63207763/article/details/142465615

相关文章

  • NGINX 和 HAProxy:基于公有云标准环境的用户体验测试对比
    原文作者:AmirRawdat-F5解决方案工程师原文链接:NGINX和HAProxy:基于公有云标准环境的用户体验测试对比转载来源:NGINX中文官网NGINX唯一中文官方社区,尽在 nginx.org.cn 阅读原文。业内许多性能基准测试,都是基于峰值吞吐量或每秒请求数(RPS),但这些......
  • 【线程】POSIX信号量---基于环形队列的生产消费者模型
    信号量概念这篇文章是以前写的,里面讲了 SystemV的信号量的概念,POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。但POSIX可以用于线程间同步。信号量的概念POSIX信号量的接口初始化信号量参数:pshared:0表示线程间共享,非0表示进程......
  • Flutter 自定义国家选择器:基于 A ~ Z字母索引的列表跳转与侧边栏导航实现
    在许多移动应用中,我们经常需要通过字母索引快速跳转到目标位置,比如通讯录、国家选择等功能。这篇博客将带大家实现一个仿照通讯录的Flutter国家选择器。通过一个字母索引的侧边栏,用户可以快速跳转到目标字母分组。效果:1.项目需求与设计思路我们需要实现一个包含多个国......
  • 基于nodejs+vue校园礼品销售系统[开题+源码+程序+论文]计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景在数字化时代,随着校园生活的日益丰富与多元化,学生对于个性化、创意化礼品的需求日益增长。然而,传统的校园礼品销售模式往往受限于时间、空间及信息不对称等......
  • 基于微信小程序的小说实体书商城-计算机毕业设计源码+LW文档
    摘  要随着互联网技术和通讯技术的快速发展、成熟,两者最终结合到了一起,即移动互联网。移动互联网时代的到来,微信的普及,致使基于微信小程序的系统越来越多,因此,针对用户手机微信购买小说书籍方面的需求,特开发了本微信小程序小说实体书商城。本微信小程序小说实体书商城采用微信......
  • 基于nodejs+vue校园零食商城系统[开题+源码+程序+论文]计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着互联网的飞速发展和数字化校园建设的不断推进,学生群体的消费习惯正悄然发生变化。传统校园内,学生购买零食往往依赖于实体小卖部或便利店,存在时间、空间......
  • 基于nodejs+vue校园论坛[开题+源码+程序+论文]计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着互联网技术的飞速发展,校园信息化已成为提升教育质量、促进师生交流的重要途径。传统校园生活中,信息的传递往往受限于时间、空间,学生间的交流互动也局限......
  • 如何部署北斗定位应用,基于国产自主架构LS2K1000LA-i处理器平台
    北斗卫星导航系统(以下简称北斗系统)是着眼于国内经济社会发展需要,自主建设、独立运行的卫星导航系统。经过多年发展,北斗系统已成为面向全球用户提供全天候、全天时、高精度定位、导航与授时服务的重要新型基础设施。图1北斗定位系统的应用优势强可控:北斗系统是国内自主研发的......
  • 基于STM32单片机的病人护理监测系统
    基于STM32单片机的病人护理监测系统0、毕业设计选题原则说明(重点)1、项目简介1.1系统功能1.2演示视频2、部分电路设计2.1STM32单片机核心板电路设计2.2DS18B20温度采集电路2.3MKB0805血压心率检测电路设计2.4、非接触式水位检测电路设计2.5、OLED显示电路设计3、单片机代码展......
  • 基于STM32单片机的厨房天然气蓝牙手机APP检测GSM短信报警系统
    基于STM32单片机的厨房天然气蓝牙手机APP检测GSM短信报警系统0、毕业设计选题原则说明(重点)1、项目简介1.1系统功能1.2演示视频2、部分电路设计2.1STM32单片机核心板电路设计2.2HC05蓝牙无线通信电路设计2.3sim900AGSM短信报警电路2.4、MQ-4天然气检测电路设计2.5、HC-SR505......