邯郸菜鸟网站建设网站建设jnlongji
news/
2025/9/24 21:17:16/
文章来源:
邯郸菜鸟网站建设,网站建设jnlongji,要看网海外域名是多少,免费制作音乐的软件app本次主要解析STM32网络通信中WebServer应用#xff0c;从网页界面的编写到浏览器与STM32之间进行通信的数据来说明SSI与CGI的原理及应用#xff0c;并对GET与POST指令进行应用解析。
硬件和软件环境#xff1a;
1.硬件环境#xff1a;STM32F407#xff0c;网卡芯片LAN87…本次主要解析STM32网络通信中WebServer应用从网页界面的编写到浏览器与STM32之间进行通信的数据来说明SSI与CGI的原理及应用并对GET与POST指令进行应用解析。
硬件和软件环境
1.硬件环境STM32F407网卡芯片LAN8720其他部分参考正点原子的407探索者开发板。
2.软件环境keil5,LWIP1.4.1主要是基于正点原子STM32F407探索者的第六十章网络通信实验程序。
一、程序流程解析
为了方便查看浏览器与STM32之间的数据通信建议程序中使用固定IP的方式如192.168.1.101建议使用软件Wireshark来查看网络数据。 首先是打开Wireshark选择本地连接 然后在地址栏输入 ip.addr 192.168.1.101,然后按右边的箭头开始接收数据 这时在浏览器输入IP地址如192.168.1.101就可以看到如下数据 这时浏览器给STM32发出GET指令数据而STM32通过函数http_recv()接收数据并把接收到的数据进行解析、处理然后把指令要求的数据发给浏览器这时浏览器上面就会显示相应的网页界面。具体在函数http_recv()里面的执行流程如下
http_recv()-----判断收到的是有效数据后调用函数http_parse_request()-----解析是GET指令还是POST指令(输入IP后下发的是GET指令)如果是GET指令则直接是调用函数http_find_file()-----判断指令的内容是请求打开默认的根文件(如打开index.shtml或test.shtml)还是CGI程序指令CGI指令主要就是在网页界面上按下按钮等下发下来的一系列相关操作指令后面再对此解说-----如指令为求打开默认的根文件则打开存放在SPI FLASH芯片W25Q128或者SD卡中的SHTML文件并获取相应的数据-----然后通过函数http_init_file()对数据进行初始化然后退出函数http_find_file()再退出函数http_parse_request()-----然后运行到函数http_send_data()查找SSI的Tag找到之后把相应的内容添加进入然后把数据发回给浏览器-----浏览器显示对应的网页界面。
打开一个网页的程序流程大概就是这样。浏览器与STM32之间的网络通信数据简单理解就是互相发送一串串字符串而一帧数据字符串里面包含了某些固定的字符串(或字符比如”GETHTTP/1.1”、”?”、””)这些字符有特定的含义而我们需要在这些字符串中找出几个特殊字符然后根据含义进行解析处理。
二、SSI的原理及应用解析
首先来了解一下SSI的原理将内容发送到浏览器之前可以使用“服务器端包含 (SSI”指令将文本、图形或应用程序信息包含到网页中。例如可以使用 SSI 包含时间/日期戳、版权声明或供客户填写并返回的表单。对于在多个文件中重复出现的文本或图形使用包含文件是一种简便的方法。将内容存入一个包含文件中即可而不必将内容输入所有文件。通过一个非常简单的语句即可调用包含文件此语句指示 Web 服务器将内容插入适当网页。而且使用包含文件时对内容的所有更改只需在一个地方就能完成。
因为包含 SSI 指令的文件要求特殊处理所以必须为所有 SSI 文件赋予 SSI文件扩展名。默认扩展名是 .stm、.shtm 和 .shtml。
以上内容来自百度简单的理解就是在把网页界面程序的SHTML文件发给浏览器之前通过某几个SSI的主要函数把SHTML里面的数据进行了替换可以说是增加了某些程序进去。而替换的规则就是查找到!--#XXX--这个XXX是可以自己定义的比如我定义LWIP_HTTPD_MAX_TAG_NAME_LEN为3那就是这!--#XXX--可以放的是3个字符比如!--#adc--然后找到这个!--#adc--后我把某个程序加上去比如加上”测试ADC”。这样可能不好理解还是直接上HTML程序首先看一个简单的SHTML程序
HTML
METAcontenttext/html; charsetgb2312 http-equivContent-Type
METAhttp-equivpragma contentno-cache
SCRIPTlanguageJavaScript!--
functiondoLoad(){
}
//--/SCRIPT
BODYοnlοaddoLoad();
FORMMETHODPOST ACTION/test.cgi
TDtest!--#adc--/TD
/FORM
/BODY
/HTML 把这个程序复制到文本文档里面然后另存为一个index.shtml然后用浏览器打开就可以看到网页界面上显示:test 这个是没有经过SSI处理的经过处理之后的SHTML程序为
HTML
METAcontenttext/html; charsetgb2312 http-equivContent-Type
METAhttp-equivpragma contentno-cache
SCRIPTlanguageJavaScript!--
functiondoLoad(){
}
//--/SCRIPT
BODYοnlοaddoLoad();
FORMMETHODPOST ACTION/test.cgi
TDtest!--#adc--测试ADC/TD
/FORM
/BODY
/HTML 用浏览器打开就可以看到网页界面上显示:test测试ADC 这样应该就能够理解了找到指定的!--#xxx--字符串后是在后面添加程序至于把这个!--#xxx--放在哪里就看怎么去编写这个SHTML程序了。
SSI的原理其实不难理解主要在httpdi_cgi_ss.c里面实际使用到的有
static constchar *ppcTAGs[] //SSI的Tag
{ t, //ADC值 w, //温度值 h, //时间 y, //日期 adc,//测试ADC
};
这个数组就是存放SSI的Tag数组在打开SHTML文件时会通过函数get_tag_insert()把SHTML里面的Tag给找出来并且添加指定的内容而添加的内容是通过函数SSIHandler()来判断然后运行指定的函数去添加而这个指定的函数比如
void ADC_Handler(char*pcInsert)
{
sprintf(pcInsert,”测试ADC”);
}
那么就可以直接达到在网页界面上的”test”后面添加”测试ADC”这样的效果。
但是有个地方要注意了如果添加的内容比较大那么就要修改
#define LWIP_HTTPD_MAX_TAG_INSERT_LEN 的大小这个就根据自己的需求来更改了如果需要增加的内容比较多改成1024甚至更大都可以。如果比实际的内容小了那会导致网页界面无法正确显示严重的会引起STM32硬件错误中断。
可能有些人对这个SHTML的数据或文件存放在哪里不是很理解先说一下目前用的一个方法就是做好成网页文件之后用makefsdata.exe来生成数组然后存放在程序里在程序里再调用。这个方法不建议用一是不直观第二是修改起来太麻烦第三是占用资源。不过有个方法和该方法类似但方便很多适用于HTML代码比较少界面比较简单的网页界面。比如
voidhttp_write_testweb(char *pbuff, int *ppos)
{ *ppos sprintf(pbuff *ppos,HTMLMETA content\text/html; charsetgb2312\http-equivContent-TypeMETA http-equiv\pragma\content\no-cache\ ); *ppos sprintf(pbuff *ppos,SCRIPT languageJavaScript!--functiondoLoad(){}//--/SCRIPT); *ppos sprintf(pbuff *ppos,BODY οnlοaddoLoad();\r\n); *ppos sprintf(pbuff *ppos,FORM METHODPOST ACTION\/test.cgi\); *ppos sprintf(pbuff *ppos,TDtest!--#adc--/TD); *ppos sprintf(pbuff *ppos,/FORM/BODY/HTML);
}
该函数直接把一个网页界面的HTML代码存入pbuff数组中代码的长度是ppos通过调用这个函数把pbuff数组的内容通过函数get_tag_insert()添加Tag的内容后再发给浏览器在浏览器上面就能看到如下的界面 另一种方法就是原子哥在第六十四章综合实例用的就是把SHTML文件存放在SPI FLASH 芯片W25Q128中然后通过FATFS文件系统直接打开调用SHTML文件目前定义的路径是#define HTTP_SRC_PATH 1:SYSTEM/LWIP/WebServer不过在网页界面调试阶段建议把路径改成SD卡下那样不用每次修改SHTML文件后总是去把文件烧进W25Q128中直接把修改好的文件放到SD卡下就可以。对于制作比较复杂的界面建议用这种方法很直观而且懂得编写HTML的话界面很快就能做出来。
三、CGI的原理及应用解析
CGI是外部应用程序CGI程序与WEB服务器之间的接口标准是在CGI程序和Web服务器之间传递信息的过程。CGI规范允许Web服务器执行外部程序并将它们的输出发送给Web浏览器CGI将Web的一组简单的静态超媒体文档变成一个完整的新的交互式媒体。
说白了STM32有了CGI处理程序之后就能和网页产生互动比如一个用户登陆界面 输入正确的用户名和密码后点击登陆按钮这时浏览器就下发一个指令数据该指令数据里面就包含了需要处理的用户名和密码数据(输入框里面的数据比如用户名是admin)STM32接收到该指令数据之后经过解析处理然后把处理之后的数据发回浏览器比如验证输入的用户名和密码为错误则在浏览器上弹出一个串口提示“用户名或密码错误”如果输入的用户名和密码为正确则在浏览器上直接跳转进入另外一个网页界面。
为了比较方便理解先看看这个登陆界面的HTML代码
HTMLMETAHTTP-EQUIV Pragma CONTENTno-cache
SCRIPTlanguageJavaScript
functiondoLoad(){
}
/SCRIPT
BODYοnlοaddoLoad();
FORM METHODPOSTACTION/checklogin.cgi
strong用户名/strong
inputtypetext size20 nameusername
strong密码/strong
inputtypepassword size20 namepassword
BR
inputtypesubmit namelogin value登陆
/FORM
/BODY
/HTML 这个代码中的FORM METHODPOST ACTION/checklogin.cgi表明浏览器是下发POST指令其中包含了checklogin.cgi处理而这个checklogin.cgi处理是要STM32在程序里面处理。直接看点击登陆之后浏览器下发给STM32的数据 从数据中可以看到”POST / checklogin.cgi”这个字符串这个就是一个POST命令在函数http_parse_request()中解析出来。而在后面的数据中有”usernameadminpasswordadminlogin%B5%C7%C2%BD”这一串数据就是要在CGI处理函数Chacklogin_CGI_Handler()中进行解析和处理并把处理的结果发回给浏览器。
在httpdi_cgi_ss.c里面有
static consttCGI ppcURLs[] //cgi程序
{ {/checklogin.cgi,Chacklogin_CGI_Handler},
};
//CGI 用户和密码检测设置 控制句柄
const char*Chacklogin_CGI_Handler(int iIndex, int iNumParams, char *pcParam[], char*pcValue[])
{ u8 i0; //注意根据自己的参数的多少来选择i值范围 u8 passchack0; iIndex FindCGIParameter(username,pcParam,iNumParams); //找到bktime的索引号 if(iIndex ! -1) //找到pagingvol索引号 { for(i 0;i iNumParams;i) { if(strcmp(pcParam,username) 0) //查找CGI参数 { if(strcmp(pcValue,admin) 0)//用户名正确 { passchack; } } elseif(strcmp(pcParam,password) 0) //查找CGI参数 { if(strcmp(pcValue,admin) 0)//密码正确 { passchack; } } } if(passchack 1)//用户名和密码都正确了 { return /index.shtml; //把保存成功的信息以及修改后的信息重新上传 } } return /error.shtml; //把保存成功的信息以及修改后的信息重新上传
}
函数Chacklogin_CGI_Handler()就是验证用户名和密码是否是”admin”正确则把index.shtml这个SHTML文件发给浏览器浏览器则显示index.shtml的网页界面如果用户名和密码错误则返回错误的网页界面(error.shtml的界面)。 关于CGI处理函数是在函数http_find_file()中解析到/checklogin.cgi后被调用而在浏览器下发的指令中有GET指令和POST指令的区别这两个指令都能够带有/checklogin.cgi但STM32对这两个指令的解析方法是不一样的这一点是要注意去区分相对来说目前的程序是直接用的GET指令来下发表单数据(就是带有FORM METHODGET ACTION/checklogin.cgi代码的网页界面)这个指令下发下来可以直接被解析出来并调用CGI处理函数但它传下来的参数会直接显示在浏览器的地址输入栏里比如“usernameadminpasswordadminlogin%B5%C7%C2%BD”这样就不是特别的安全所以不建议用次方法下发表单数据。而用POST指令下发则不会这样相对来讲会更安全而且如果是下发一个文件的数据比如做网络升级时下发的bin文件这个时候就是得用POST指令。所以接下来重点介绍POST指令的应用。
四、GET与POST指令的应用解析 GET和POST是两种最常用的HTTP请求方法。我们日常生活中“打开网页”的操作相当于“使用GET方法获取服务器资源”而“上传附件”、“提交表格”等操作相当于“使用POST将本地资源提交给服务器”。似乎GET方法和POST方法的区别就是一个用于“索取”一个用于“递交”。这么说也对也不对实际使用中确实有部分程序这样使用了但是HTTP协议设计时可不是这样考虑的下面的表格简单对比了两者的一些差异。 GET 方法 POST 方法 可传递数据类型 ASCII文本汉字有专门的方法转换 不限支持二进制文件 可传送的数据量 有限制2048字节减去URL长度 无限制 内容编码类型 application/x-www-form-urlencoded application/x-www-form-urlencoded或multipart/form-data 后退/刷新 回退后再次前进或刷新不会通知用户 数据会被再次提交 历史记录 浏览器会记录全部内容 浏览器只记录接收POST内容的URL但不记录POST的具体内容 典型应用 获取服务器上的资源如下载 向服务器添加资源如上传附件 在网页界面中应用GET与POST的区别基本在与表单那里如使用GET指令为
FORM METHODGET ACTION/checklogin.cgi
使用POST指令为
FORM METHODPOST ACTION/checklogin.cgi
在STM32中要使用POST指令需要先设置
#defineLWIP_HTTPD_SUPPORT_POST 1然后还需要注意的是
#definePBUF_POOL_BUFSIZE 1600这个大小不能太小因为一帧数据最大是1514小于1514会导致接收到的数据出现错误这个设置主要在文件上传时尤其需要注意因为文件数据基本都是1514字节一帧数据的发给STM32。
打开#define LWIP_HTTPD_SUPPORT_POST 1后需要编写接收和解析POST指令的三个函数
err_thttpd_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)
{ memset(http_post_response_filename,0,sizeof(http_post_response_filename)); strcpy(response_uri,uri); return ERR_OK;
} err_thttpd_post_receive_data(void *connection, struct pbuf *p)
{ struct http_state *hs(struct http_state*) connection; *(strrchr(p-payload,)) 0; sprintf(http_post_response_filename strlen(http_post_response_filename),?%s,p-payload); return ERR_MEM;//不回复ERR_OK为了让外面的函数能够调用http_handle_post_finished()
} voidhttpd_post_finished(void *connection, char *response_uri, u16_tresponse_uri_len)
{ }
static err_thttp_handle_post_finished(struct http_state *hs)
{ /* application error or POST finished */ /* NULL-terminate the buffer */
// http_post_response_filename[0] 0;//数据处理已经在httpd_post_begin()和httpd_post_receive_data()函数里处理
// httpd_post_finished(hs,http_post_response_filename, LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN); return http_find_file(hs, http_post_response_filename,0);
}
这三个函数的写法可以有很多种目前我这样写只是为了方便直接使用函数http_find_file()中对CGI的判断解析方法GET指令时的解析方法。如果使用的是GET指令下发CGI则在函数http_find_file()中uri[]这个数组里面可以找到” ?usernameadminpasswordadminlogin%B5%C7%C2%BD”所以找到”?”这个字符就表明找到了第一个参数的地址。而使用POST指令时下发的数据中uri[]数组中是”usernameadminpasswordadminlogin%B5%C7%C2%BD”没有这个”?”所以为了方便使用函数http_find_file()所在在函数httpd_post_receive_data()中人为的添加了”?”并且找到倒数第一个””就是只要” ?usernameadminpasswordadmin”当然也可以不这么写但原理是一样的目的就是找出” usernameadminpasswordadmin”这些参数然后把参数给赋值到hs中比如把username存入hs-params[0]中把admin存入hs-param_vals[0]具体看函数extract_uri_parameters()。然后在接下来的处理就是在函数http_handle_post_finished()调用函数http_find_file()来找到并调用对应的CGI函数比如调用函数Chacklogin_CGI_Handler()。
最后来看一下浏览器下发POST指令时STM32的解析流程
http_recv()-----判断收到的是有效数据后调用函数http_parse_request()-----解析是GET指令还是POST指令(输入IP后下发的是GET指令)如果是POST指令则调用函数http_post_request ()-----然后用函数httpd_post_begin()开始处理数据-----然后调用函数http_post_rxpbuf()-----再调用函数httpd_post_receive_data()处理接收到的数据 这时是人为添加”?”-----处理结束后是调用函数http_handle_post_finished()这个函数中其实也就是调用函数http_find_file()来解析CGI程序指令也就是找到并调用对应的CGI函数比如Chacklogin_CGI_Handler()-----由于调用的CGI处理函数的返回值是一个shtml的文件路径该文件是存放在SPIFLASH芯片W25Q128或者SD卡中的SHTML文件获取相应的数据-----然后通过函数http_init_file()对数据进行初始化然后退出函数http_find_file()再退出函数http_parse_request()-----然后运行到函数http_send_data()查找SSI的Tag找到之后把相应的内容添加进入然后把数据发回给浏览器-----浏览器显示CGI处理后的网页界面。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/916252.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!