最近在做stm32 web服务器的东西,忙了一段时间终于弄完了,把这几天关于stm32服务器的工作记录一下。
刚接到这个任务的时候,不知道怎么下手,网上资料似乎不是很多,于是在下载了一个官方demo测试了一下,看了一下代码,不是很懂,于是继续百度找资料,找到一个比较有用的网页,以下是链接: 最近在做stm32 web服务器的东西,忙了一段时间终于弄完了,把这几天关于stm32服务器的工作记录一下。刚接到这个任务的时候,不知道怎么下手,网上资料似乎不是很多,于是在下载了一个官方demo测试了一下,看了一下代码,不是很懂,于是继续百度找资料,找到一个比较有用的网页,以下是链接:http://wenku.baidu.com/link?url=SfAxsft0bXxvaoeDtSGCLlnB3yQNhofQfLwfO9l-aZmTsVy2haookGZI6VP4WGlnr26Fx_BxakWV3oMQbKl54FQyssKDy2fRxI5JnIXaPgK
其实,stm32 web服务器与pc网页的交互一般是以表单的方式,就两个接口,cgi和ssi。这两个东西我的理解是这样的,cgi 就是pc网页向stm32 web服务下发信息的接口,比如我们有这样的一个网页:
<form method='get' action='config.cgi'>
<p><label for='ip'>ip:label>" maxlength="1" />p>
<p><label for='port'>port:label>" maxlength="6" />
p><p><input type='submit' value='保存' />p>
form>
如果看不懂这个网页的话,就百度一下吧,把上面东西复制到Macromedia Dreamweaver 8软件上就能看到是什么页面,上面在form就是表单,在<form>form>里面的内容就是表单的内容,里面有两个输入框,和一个保存按钮,当我们点出保存的时候就会在web服务器里触发,config.cgi的接口,关于web服务器的内容,后面再说,然后会把这个表单里的内容下发到服务器里,比如会把上面ip和port输入框中的数据发到web服务器里,web服务器就能获得想要的数据。接下来说一下ssi,我们可以拿个网络抓包软件观察一下,pc网页的web服务器的通信过程,其实也就是pc发送一个请求,然后web服务器返回一组数据,这组数据就是整个网页的内容。ssi的工作就是在这组返回的数据中嵌入一个要发送加pc端的数据在里面,比如刚才那个表单网页数据,我们要显示一些数据到ip输入框中,怎么办呢?在没有ssi接口的时候可以看到,
<p><labelfor='ip'>ip:label>" maxlength="1" />p> ,
有ssi接口时候,我们就可以利用ssi接口改变返回的内容,比如:
<p><labelfor='ip'>ip:label>192.168.1.1" maxlength="1" />p>,
可以看到 "192.168.1.1" 这个地方是不相同的,这时返回ip输入框是带着数据的,这个数据将显示在ip输入框内。
接下来分析一下代码,首先看一下stm32官方http web 包里的文件
fsdata.c,fsdata.h,是网页转换成的数组,
fs.c, fs.h是操作fsdata.c里面数据的一些读写函数
httpd.c, httpd.h函数是真正实现web服务器的文件
httpd_cgi_ssi.c, httpd_cgi_ssi.h 就是刚才提到的cgi, ssi接口,
一般我们只需要改动httpd_cgi_ssi.c, fsdata.c(这个文件是makefsfile.exe生成的),
makefsfile里面又有一些什么文件呢
fs文件夹是所有的网页,fsdata.c 是用makefsfile.exe转换得到的
下面分析一下代码
1. void httpd_init(void)
{
LWIP_DEBUGF(HTTPD_DEBUG, ("httpd_init\n"));
#if LWIP_HTTPD_SSI
httpd_ssi_init(); //ssi接口初始化
#endif
#if LWIP_HTTPD_CGI
httpd_cgi_init(); //cgi接口初始化
#endif
httpd_init_addr(IP_ADDR_ANY); //http web 相关初始化
}
2.ssi接口 要注意的一点就是 有ssi接口的网页要以 shtml为后缀
char const* TAGS[]={ //这里定义了ssi标签,
"ip", //ip地址 对应网页里的
"sp", //服务器端口
};
u16_t DeviceSSI_Handler(int iIndex, char *pcInsert, int iInsertLen)
{
int len = 0;
char buff[16];
memset(buff,0,sizeof(buff));
switch(iIndex)
{
case 0: //这个index是在数组中的位置
sprintf(buff,"%s",“192.168.1.1”);
len = strlen(buff);
memcpy(pcInsert,buff,len);// 这里是拷贝填充在ip标签里的内容
break;
case 1:
。。。。。。
break;
}
return len;
}
3.cgi接口
//cgi接口定义
tCGI CGI_TAB[]={
{"/login.cgi", LOGIN_CGI_Handler},
{"/saveNet.cgi", SAVE_NET_Handler} /*这里的cginame要和网页表单里的action相同<form method='get' action='config.cgi'>*/
};
const char * SAVE_NET_Handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[])
{
uint32_t i=0;
for (i=0; i
if(strcmp(pcParam[i]/*参数名字,与网页里控件的name相同name='ip'*/,"ip") == 0) //设备ip
{
printf("ip is : %s \r\n",pcValue[i]/*控件的值*/);
}
else if(strcmp(pcParam[i],"port") == 0)
{
...
}
......
}
cgi和ssi大概就这些内容要改的,
4.打开网页里是哪一个为首页呢?在httpd.c里有一个数据
//这里设置首页显示的html ,所以首页就是login
const default_filename g_psDefaultFilenames[] = {
{"/login.shtml", true },
{"/login.ssi", true },
{"/login.shtm", true },
{"/login.html", false },
{"/login.htm", false }
};
5.我们发送ssi标签时会把标签一起发上去,这样在编辑控件里是会把标签一起显示的,比如value="192.168.1.1",这不是我们想要的,怎么让它不发送标签呢,
把httpd.c里的定义 #define LWIP_HTTPD_SSI_INCLUDE_TAG 1 //改为0就不发送标签
6.还有一些比较常用的宏定义
#define LWIP_HTTPD_MAX_CGI_PARAMETERS 16 //cgi数量定义
#define LWIP_HTTPD_MAX_TAG_NAME_LEN 8 //定义tag标签长度定义
#define LWIP_HTTPD_MAX_TAG_INSERT_LEN 192 //定义返回tag内容长度