嵌入式linux设备,尤其是做数据采集的设备,例如我说过的汽车电标识数据的采集,以及以前做的水文数据采集,海洋气象数据采集等嵌入式linux设备出于成本和功耗的考虑,均不会配备显示屏。那么要想让用户直观的看到设备内的配置状态以及数据采集的状态,通常就是在嵌入式linux上运行一个小型的http服务器软件,通过网页也显示这些。例如,当前常用的thttp。或稍大型的apache tomcat。然而,这些http服务器很难和嵌入式linux上运行的c或c++程序无缝衔接起来。通常都是利用文件的形式,与c或c++程序进行衔接。此种方法当然能用,但存在很多问题。我一直在寻找一个合适的方法。
2023底的时候,因为公司项目需要一个开源的c的websocket服务器,经过一番常找和验证,发现了一个c语言写的http开源库——mongoose。官方网址是https://mongoose.ws/。这个库很适合用在嵌入式linux上,整个的库就是两个文件,mongoose.c,mongoose.h文件。它的使用简单,很容易就嵌入到你的c或c++的项目中,此库可实现一个小型的http服务器,或基于http的websocket服务器,或同样基于http的RESTful服务器,也可以实现tcp的通信。
这里总结一下用mongoose做http服务器来实现设备配置页面的方法。在嵌入式linux上,要做配置页面,当然第一步是能够显示网页工程师们做好的静态页面。要做到这点,mongoose很容易就能办到,它能正常处理带css,js等文件的页面,显示jpeg更是不在话下。
显示网页的话,用mg_http_serve_dir函数,在传入的mg_http_serve_opts参数中,指定web的根目录。然后,就可正常显示静态网页了。
当然,仅仅显示页面肯定是不够的,在嵌入式设备的配置页面中,要用post,put方法,将工作参数等提交给设备。
这样,还需在mg_http_listen函数中,传入mg_event_handler_t函数指针,在这个函数中,定议post,put的处理方法。
我把整个代码贴出来给大家分享。
嵌入式linux设备,尤其是做数据采集的设备,例如我说过的汽车电标识数据的采集,以及以前做的水文数据采集,海洋气象数据采集等嵌入式linux设备出于成本和功耗的考虑,均不会配备显示屏。那么要想让用户直观的看到设备内的配置状态以及数据采集的状态,通常就是在嵌入式linux上运行一个小型的http服务器软件,通过网页也显示这些。例如,当前常用的thttp。或稍大型的apache tomcat。然而,这些http服务器很难和嵌入式linux上运行的c或c++程序无缝衔接起来。通常都是利用文件的形式,与c或c++程序进行衔接。此种方法当然能用,但存在很多问题。我一直在寻找一个合适的方法。
2023底的时候,因为公司项目需要一个开源的c的websocket服务器,经过一番常找和验证,发现了一个c语言写的http开源库——mongoose。官方网址是https://mongoose.ws/。这个库很适合用在嵌入式linux上,整个的库就是两个文件,mongoose.c,mongoose.h文件。它的使用简单,很容易就嵌入到你的c或c++的项目中,此库可实现一个小型的http服务器,或基于http的websocket服务器,或同样基于http的RESTful服务器,也可以实现tcp的通信。
这里总结一下用mongoose做http服务器来实现设备配置页面的方法。在嵌入式linux上,要做配置页面,当然第一步是能够显示网页工程师们做好的静态页面。要做到这点,mongoose很容易就能办到,它能正常处理带css,js等文件的页面,显示jpeg更是不在话下。
显示网页的话,用mg_http_serve_dir函数,在传入的mg_http_serve_opts参数中,指定web的根目录。然后,就可正常显示静态网页了。
当然,仅仅显示页面肯定是不够的,在嵌入式设备的配置页面中,要用post,put方法,将工作参数等提交给设备。
这样,还需在mg_http_listen函数中,传入mg_event_handler_t函数指针,在这个函数中,定议post,put的处理方法。
我把整个代码贴出来给大家分享。
#include "mongoose.h"
#include <string>
#include <iostream>
#include <regex>
using namespace std;
// 设置一个数据文件路径
char * dataPath = "c:/home/test";
static const char *s_http_addr = "http://localhost:8000"; // HTTP port
static const char *s_root_dir = dataPath;
void eventHandler(struct mg_connection *c, int ev, void * ev_data, void *fn_data) {
if (ev != MG_EV_HTTP_MSG) return;
struct mg_http_message *hm = (struct mg_http_message *)ev_data;
string hm_str = hm->method.ptr;
//printf("Method:%s\n",hm_str.c_str());
hm_str = hm->head.ptr;
//printf("Head:%s\n",hm_str.c_str());
hm_str = hm->uri.ptr;
//printf("Uri:%s\n",hm_str.c_str());
// 检查HTTP方法是否为Get
if (mg_vcmp(&hm->method, "GET") == 0) {
// 这是一个Get请求
printf("Received a Get request\n");
if(mg_http_match_uri(hm, "/api/hello")) {
char res[1024] = {0x00};
mg_http_reply(c, 200, "", "<html><head><title>mongoose demo</title></head><body><h1>Hello Mongoose!</h1></body></html>\n");
printf("Reply Get hello!\n");
}
else{ //Get访问其它路径,默认的内容,这里是下载文件
printf("Get file....\n");
string uri = hm->uri.ptr;
string data;
//data = midstr(head, "GET", "HTTP/1.1");
int npos = uri.find("HTTP/1.1");
data = uri.substr(0,npos);
cout <<"|"<< data <<"|"<< endl;
string path = dataPath +data ;
printf("path=%s\n",path.c_str());
// 调用mg_http_serve_file返回文件
struct mg_http_serve_opts opts = {.root_dir = s_root_dir};
mg_http_serve_dir(c, hm, &opts); //实践证明,此处不能用mg_http_serve_file函数,否则会导致css文件不能被正确识别下载,中文编码方式也不对
}
}else if(mg_vcmp(&hm->method, "POST") == 0){
//post请求示例,请求体json示例{"a":10,"b":20},计算a+b的值
if (mg_http_match_uri(hm, "/api/sum")) {
// 简单post请求,加法运算测试
char n1[100], n2[100];
double result;
/* Get form variables */
mg_http_get_var(&hm->body, "n1", n1, sizeof(n1));
mg_http_get_var(&hm->body, "n2", n2, sizeof(n2));
/* Compute the result and send it back as a JSON object */
result = strtod(n1, NULL) + strtod(n2, NULL);
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"result\":%lf}", result);
printf("POST:result=%f\n",result);
}
}
else if(mg_vcmp(&hm->method, "PUT") == 0)
{
char n3[100];
mg_http_get_var(&hm->body, "n3", n3, sizeof(n3));
double result = strtod(n3, NULL);
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"result\":%lf}", result);
printf("PUT:result=%f\n",result);
}
else {
// 这是一个其它请求
printf("This is a other request\n");
mg_http_reply(c, 403, "", "Method not handled!\n");
}
}
int main(int argc, char **argv) {
struct mg_mgr mgr;
mg_mgr_init(&mgr);
// 初始化ip和回调函数,这里端口号可以任选一个没被占用的
mg_http_listen(&mgr, "http://127.0.0.1:8001", eventHandler, &mgr);
// 进入事件循环,1s一次
while (true) {
mg_mgr_poll(&mgr, 1000);
}
// 清理
mg_mgr_free(&mgr);
return 0;
}
使用这段代码的方法是在c:/home/test/ 下入一个index.html的静态网页就可显示。
mongoose是在win和linux平台都能被编译成功的。在win平台下,建议用QT5新建一个None-QT project。然后,在项目文件pro中加入LIBS += -lWs2_32这句,即可成功编译。 注:这里要特别说明的是,如果你是用c来调用mongoose的话,编译器会报错,说是某些方法需要c99的支持。此时,在pro文件中加入CONFIG += c99 ,即可解决问题。