admin管理员组文章数量:1794759
CubeMX配置STM32实现httpd服务器CGI功能并使用网页控制STM32单片机(四)
CubeMX配置STM32实现httpd服务器CGI功能并使用网页控制STM32单片机
- 引言
- CubeMX配置HTTPD的CGI功能
- 实验过程
- 发现的问题
- 总结
在前三篇文章中自己介绍了如何配置freeRTOS以及如何配置LWIP,并使用lwip实现一个httpd服务器,使浏览器可以访问。在本章中我们利用CGI功能,实现通过网页来控制单片机的一个LED灯的电平翻转。
自己写的另外五篇文章 从零开始Cubemx配置STM32搭载freeRTOS实现多路ADC(一) 从零开始Cubemx配置STM32搭载freeRTOS以及lwip实现tcp网络通信(二) 从零开始使用CubeMX配置STM32使用lwip实现httpd服务器以及使用vscode编辑阅读keil代码(三) CubeMX配置STM32实现FatFS文件系统(五) CUBEMX配置STM32实现FTP文件传输以及使用SNTP获取网络时间并写入RTC
CubeMX配置HTTPD的CGI功能在这里把CGI功能开启。 CGI的介绍部分参考这位老哥的文章 blog.csdn/weixin_39517902/article/details/111205216
CGI是common gateway interface的缩写,大家都译作通用网关接口,但很不幸,我们无法见名知意。
我们知道,web服务器所处理的内容都是静态的,要想处理动态内容,需要依赖于web应用程序,如php、jsp、python、perl等。但是web
server如何将动态的请求传递给这些应用程序?它所依赖的就是cgi协议。没错,是协议,也就是web
server和web应用程序交流时的规范。换句话说,通过cgi协议,再结合已搭建好的web应用程序,就可以让web
server也能"处理"动态请求(或者说,当用户访问某个特定资源时,可以触发执行某个web应用程序来实现特定功能),你肯定知道处理两字为什么要加上双引号。
简单版的cgi工作方式如下:
例如,在谷歌搜索栏中搜索一个关键词"http",对应的URL为:
www.google/search?q=http&oq=http&aqs=chrome…69i57j69i60l4j0.1136j0j8&sourceid=chrome&ie=UTF-8
当谷歌的web
server收到该请求后,先分析该url,从中知道了要执行search程序,并且还知道了一系列要传递给search的参数及其对应的value。web
server会将这些程序参数和其它一些环境变量根据cgi协议通过TCP或套接字等方式传递给已启动的cgi程序(可能是cgi进程,或者是已加载的模块cgi模块)。当cgi进程接收到web
server的请求后,调用search程序并执行,同时还会传递参数给search程序。search执行结束后,cgi进程/线程将处理结果返回给web
server,web server再返回给浏览器。
有多种方式可以执行cgi程序,但对http的请求方法来说,只有get和post两种方法允许执行cgi脚本(即上面的search程序)。实际上post方法的内部本质还是get方法,只不过在发送http请求时,get和post方法对url中的参数处理方式不一样而已。
实验过程在这里我新建一个文件命名为apimain.c
#include "apimain.h" #include "httpd.h" #include <stdio.h> static const char *api_operation_req(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]); //核心就是根据URL的参数来执行不同的处理函数 static const tCGI g_psConfigCGIURIs[] = { {"/img/sics.gif", api_operation_req}, }; const char *api_operation_req(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) { // HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, GPIO_PIN_RESET); HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_3); printf("cgi success!!!!\\n"); } void api_server_init(void) { httpd_init(); //这是CGI的初始化 http_set_cgi_handlers(g_psConfigCGIURIs, sizeof(g_psConfigCGIURIs)/sizeof(tCGI)); }应用CGI的核心就是根据URL的参数来执行不同的处理函数,比如请求的URL是192.168.0.205/img/sics.gif ,我就是利用了这个GET请求,来实现一个LED灯的电平翻转,刷新网页的时候会执行这个请求。 CGI具体实现在httpd.c的http_find_file( )函数中,主要是下面几句,可以看到与URL的字符串进行对比,如果一样就进入CGI的这个句柄分支。
#if LWIP_HTTPD_CGI http_cgi_paramcount = -1; /* Does the base URI we have isolated correspond to a CGI handler? */ if (httpd_num_cgis && httpd_cgis) { for (i = 0; i < httpd_num_cgis; i++) { if (strcmp(uri, httpd_cgis[i].pcCGIName) == 0) { /* * We found a CGI that handles this URI so extract the * parameters and call the handler. */ http_cgi_paramcount = extract_uri_parameters(hs, params); uri = httpd_cgis[i].pfnCGIHandler(i, http_cgi_paramcount, hs->params, hs->param_vals); break; } } }刷新网页请求的url是/img/sics.gif,因此我的apimain.c写的就是,这样执行这个请求的时候就会进api_operation_req()这个函数。这样我们就实现了使用网页的请求来控制单片机和其他设备。
static const tCGI g_psConfigCGIURIs[] = { {"/img/sics.gif", api_operation_req}, }; 发现的问题LWIP的HTTPD服务没有实现POST的相关处理,但是httpd.h中已经进行了声明,但是在httpd.c中没有进行具体的实现,这里坑我了一下,我没仔细看,开启LWIP_HTTPD_SUPPORT_POST的宏后,编译不过去,如果想要支持POST操作的话,要自己写函数的实现,主要是这三个函数,网上有具体的实现。
#if LWIP_HTTPD_SUPPORT_POST /* These functions must be implemented by the application */ /** * @ingroup httpd * Called when a POST request has been received. The application can decide * whether to accept it or not. * * @param connection Unique connection identifier, valid until httpd_post_end * is called. * @param uri The HTTP header URI receiving the POST request. * @param http_request The raw HTTP request (the first packet, normally). * @param http_request_len Size of 'http_request'. * @param content_len Content-Length from HTTP header. * @param response_uri Filename of response file, to be filled when denying the * request * @param response_uri_len Size of the 'response_uri' buffer. * @param post_auto_wnd Set this to 0 to let the callback code handle window * updates by calling 'httpd_post_data_recved' (to throttle rx speed) * default is 1 (httpd handles window updates automatically) * @return ERR_OK: Accept the POST request, data may be passed in * another err_t: Deny the POST request, send back 'bad request'. */ err_t httpd_post_begin(void *connection, const char *uri, const char *http_request, u16_t http_request_len, int content_len, char *response_uri, u16_t response_uri_len, u8_t *post_auto_wnd); /** * @ingroup httpd * Called for each pbuf of data that has been received for a POST. * ATTENTION: The application is responsible for freeing the pbufs passed in! * * @param connection Unique connection identifier. * @param p Received data. * @return ERR_OK: Data accepted. * another err_t: Data denied, http_post_get_response_uri will be called. */ err_t httpd_post_receive_data(void *connection, struct pbuf *p); /** * @ingroup httpd * Called when all data is received or when the connection is closed. * The application must return the filename/URI of a file to send in response * to this POST request. If the response_uri buffer is untouched, a 404 * response is returned. * * @param connection Unique connection identifier. * @param response_uri Filename of response file, to be filled when denying the request * @param response_uri_len Size of the 'response_uri' buffer. */ void httpd_post_finished(void *connection, char *response_uri, u16_t response_uri_len); #if LWIP_HTTPD_POST_MANUAL_WND void httpd_post_data_recved(void *connection, u16_t recved_len); #endif /* LWIP_HTTPD_POST_MANUAL_WND */ #endif /* LWIP_HTTPD_SUPPORT_POST */ 总结到此,通过这四篇文章,我实现了从零使用CUBEMX配置了一个带有FREERTOS以及LWIP和带有CGI功能的HTTPD服务器,以后如果想使用物联网设备开启局域网服务器,就可以使用这个框架。在这里我已经把框架搭好,可以根据需求进行下一步完善。 下一步我完善主要是需要与前端进行沟通,设计网页的API,如一个开门操作。通过这样的请求,利用CGI,完成比较复杂的操作。 本文提供的更多是一种思路,因为加入了操作系统,不只适用于单片机,只有是嵌入式设备都可以用,因为操作系统,lwip协议栈都是相同的。这个项目到此为止,希望有帮助的话多多点赞,收藏和评论。
版权声明:本文标题:CubeMX配置STM32实现httpd服务器CGI功能并使用网页控制STM32单片机(四) 内容由林淑君副主任自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.xiehuijuan.com/baike/1686747646a97876.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论