最近由于项目功能需要,开始研究STM32 WebServer通信以及SSI和CGI应用方法。项目结束后,主要总结浏览器与STM32之间进行通行,STM32作为服务器而浏览器做为客户端进行通行。
此部分的代码是根据ST官方的Web Server例程的基础上完成修改和实现,在webserver文件夹下:
文件 | 说明 |
---|---|
makefsdata | 文件夹中包含有原始网页文件和将原始的网页文件转化成网页数据的工具makefsdata.exe |
fs.c | 这两个文件用来管理生成的网页数组 |
fs.h | |
fsdata.c | 生成的网页数组 |
fsdata.h | |
httpd.c | Http Server的源代码,本实验的核心文件,这两个文件完成了将开发板配置成Web Serve的工作 |
httpd.h | |
httpd_cgi_ssi.c | CGI和SSI源文件,我们通过网页和开发板交互主要是这个文件中的函数完成的 |
在makefsdata文件下的fs文件为网页源文件,如图所示,其中index.shtml文件时主页面,其他页面都是辅助和跳转页面。
公共网关接口 CGI(Common Gateway Interface) 是 WWW 技术中最重要的技术之一,有着不可替代的重要地位。CGI 是外部应用程序与 Web 服务器之间的接口标准,是在 CGI 程序和Web 服务器之间传递信息的规程。CGI 规范允许 Web 服务器执行外部程序,并将它们的输出发送给 Web 浏览器,CGI 在物理上是一段程序,运行在服务器上,提供同客户端 HTML 页面的接口。
绝大多数的 CGI 程序被用来解释处理来自表单的输入信息,并在服务器产生相应的处理,或将相应的信息反馈给浏览器,CGI 程序使网页具有交互功能。在我们本章实验中我们通过浏览器控制开发板上的 LED 和蜂鸣器就是使用的 CGI 技术。
服务器端嵌入:Server Side Include,是一种类似于 ASP 的基于服务器的网页制作技术。大多数的 WEB 服务器等均支持 SSI 命令。将内容发送到浏览器之前,可以使用“服务器端包含(SSI)”指令将文本、图形或应用程序信息包含到网页中。例如,可以使用 SSI 包含时间/日期戳、版权声明或供客户填写并返回的表单。对于在多个文件中重复出现的文本或图形,使用包含文件是一种简便的方法。将内容存入一个包含文件中即可,而不必将内容输入所有文件。通过一个非常简单的语句即可调用包含文件,此语句指示 Web 服务器将内容插入适当网页。而且,使用包含文件时,对内容的所有更改只需在一个地方就能完成。因为包含 SSI 指令的文件要求特殊处理,所以必须为所有 SSI 文件赋予 SSI 文件扩展名。默认扩展名是 .stm、.shtm 和 .shtml。
SSI 是为 WEB 服务器提供的一套命令,这些命令只要直接嵌入到 HTML 文档的注释内容之中即可。如: 就是一条 SSI 指令,其作用是将"info.htm"的内容拷贝到当前的页面中,当访问者来浏览时,会看到其它 HTML 文档一样显示 info.htm 其中的内容。其它的 SSI 指令使用形式基本同刚才的举例差不多,可见 SSI 使用只是插入一点代码而已,使用形式非常简单。 是 HTML 语法中表示注释,当 WEB 服务器不支持 SSI 时,会忽略这些信息。
1)在httpd.h文件中有如下宏定义需要注意修改
/*CGI的handler可以发送的最大参数数量 The maximum number of parameters that the CGI handler can be sent. */
#define LWIP_HTTPD_MAX_CGI_PARAMETERS 16
/* SSI的Tag 最长字节 单位字节*/
#define LWIP_HTTPD_MAX_TAG_NAME_LEN 5
2)在httpd_cgi_ssi.c文件中有如下宏定义需要注意
#define NUM_CONFIG_CGI_URIS 1 //CGI的URI数量 发送的个数
#define NUM_CONFIG_SSI_TAGS 7 //SSI的TAG数量 发送的个数
/*SSI的Tag 长度由LWIP_HTTPD_MAX_TAG_NAME_LEN宏定义确定*/
static const char *ppcTAGs[]=
{
"IPad",//IP地址 //长度4字节
"coIP",//计算机IP地址
"ponu",//端口号
"eqnu",//设备编号
"sosi",//软件版本
"upti",//更新时间间隔
"late",//车道检测方式
};
/*CGI的Tag*/
static const tCGI ppcURLs[]=
{
{"/config.cgi",Device_Setting_CGI_Handler},
};
/*初始化httpd,建立一个监听PCB并且绑定到指定的端口上*/
void httpd_init(void)
{
LWIP_DEBUGF(HTTPD_DEBUG, ("httpd_init\n"));
#if LWIP_HTTPD_SSI
httpd_ssi_init();
#endif
#if LWIP_HTTPD_CGI
httpd_cgi_init();
#endif
httpd_init_addr(IP_ADDR_ANY);
}
/*SSI句柄初始化*/
void httpd_ssi_init(void)
{
//配置SSI句柄
http_set_ssi_handler(SSIHandler,ppcTAGs,NUM_CONFIG_SSI_TAGS);
}
/*CGI句柄初始化*/
void httpd_cgi_init(void)
{
//配置CGI句柄
http_set_cgi_handlers(ppcURLs, NUM_CONFIG_CGI_URIS);
}
此处源码是index.shtml文件的源码主要是登录界面源码
DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>用户登录title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: inline-block;
min-width: 70px;
}
.form-group input {
height: 32px;
line-height: 32px;
}
style>
head>
<body>
<div class="container" style="width: 330px; padding-top: 130px">
<h2 style="text-align: center">用户登录h2>
<form id="loginForm" method="get" action="/register.cgi">
<div class="form-group">
<label for="username">用户名:label>
<input
type="text"
name="username"
class="form-control"
id="username"
placeholder="请输入用户名"
autocomplete="off"
/>
div>
<div class="form-group">
<label for="password">密码:label>
<input
type="password"
name="password"
class="form-control"
id="password"
placeholder="请输入密码"
autocomplete="off"
/>
div>
<div class="form-group" style="text-align: center">
<button
class="btn btn-lg btn-primary btn-block"
type="submit"
value="登录"
>
用户登录
button>
div>
form>
div>
body>
html>
登录CGI控制句柄源码,主要用于判断接受的数据是否正确
//登录界面CGI控制句柄
const char* Register_CGI_Handler(int iIndex,int iNumParams,char *pcParam[],char *pcValue[]){
INT8U i=0,passchack=0;
iIndex = FindCGIParameter("username",pcParam,iNumParams); //找到登录页面 索引号
/* 打印接受的数据
printf("index:\r\n");
for(i =0 ;i < iNumParams; i++){
printf("pcParam[%d]:%s\r\n",i,pcParam[i]);
printf("pcValue[%d]:%s\r\n",i,pcValue[i]);
}
printf("\r\n");*/
if(iIndex != -1){
for (i=0; i<iNumParams; i++){
if(strcmp(pcParam[i],"username") == 0){ //检查用户CGI参数
if(strcmp(pcValue[i],"admin") == 0){ //用户名正确
passchack++;
}
}else if(strcmp(pcParam[i],"password") == 0){ //检查密码CGI参数
if(strcmp(pcValue[i],"admin123456") == 0){ //密码正确
passchack++;
}
}
}
if(passchack == 2){
//用户名和密码正确进入数据显示界面
return "/baseData.shtml";//输入正确 跳转到其他页面
}
}
return "/index.shtml";//账号和密码输入错误,返回登录界面
}