ESP8266搭建简易web服务器
ESP8266是个集成了LWIP协议栈的WIFI模块,利⽤它很容易就完成了物联⽹的功能。
要搭建web服务器就必须⽀持HTTP协议。
但是ESP8266官⽹提供的例⼦只能⽀持TCP,不直接⽀持HTTP。
那么,就需要⾃⼰利⽤TCP来完成HTTP的请求包和响应包。
⼀、搭建ESP8266的SDK开发环境。
下载并安装集成IDE,。
下载并安装。
下载并解压官⽅提供的SDK例⼦,。
⼆、利⽤IoT Demo来完成TCP协议。
进⼊esp8266_nonos_sdk⽬录,把driver_lib⽬录改名为app,把examples->IoT_Demo中的所有⽂件及⽂件夹都拷贝到app⽬录下(直接覆盖)。
在AiThinker_IDE下,打开esp8266_nonos_sdk⼯程,编译(Build Project),⽣成.bin⽂件。
⽤ESPFlashDownloadTool烧写该.bin⽂件,可以在WiFi中看到ESP8266的热点,此为开放热点,可以直接连接。
每次编译成功,IDE都会提⽰.bin⽂件的烧写地址,如下图所⽰,eagle.flash.bin->0x00000,0text.bin->0x10000,把这些⽂件的路径和地址填在烧写⼯具就可以了。
把ESP8266的GPIO0置低,GPIO2置⾼,GPIO15置低,重新上电,即可进⼊烧写模式。
能看到ESP8266的热点,说明硬件已经没有问题了。接下来要修改SDK的源码。
三、利⽤TCP协议来完成HTTP协议。
在NONOS⼯程中新建user_tcpserver.c⽂件,并添加下⾯的代码。
#include "osapi.h"
#include "at_custom.h"
#include "user_interface.h"
#include "espconn.h"
#include "ets_sys.h"
#include "mem.h"
uint8_t http_head[] = {
"HTTP/1.0 200 OK\r\n"\
"Content-Type: text/html;charset=gbk\r\n"\
"Cache-Control: private\r\n"\
"Connection: close\r\n"\
"\r\n"\
"<!DOCTYPE html>"\
"<html>" \
"<head>" \
"<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">" \
"<meta name=\"viewport\" content=\"width=device-width,height=device-height,inital-scale=1.0,maximum-scale=1.0,user-scalable=no;\">" \  "<meta name=\"renderer\" content=\"webkit|ie-comp|ie-stand\">" \
"<meta name=\"apple-mobile-web-app-capable\" content=\"yes\">" \
"<meta name=\"apple-mobile-web-app-status-bar-style\" content=\"black\">" \
"<meta name=\"format-detection\" content=\"telephone=no\">" \
"<meta content=\"email=no\" name=\"format-detection\" />" \
"<title></title>" \
"</head>" \
"<style type=\"text/css\">" \
"body{overflow-x:hidden;}" \
"img{width: 100%;display: block;}" \
"</style>" \
"<body>" \
"<a>点击按钮</a>" \
"<form action=\"\" method=\"post\">" \
"<button name=\"btn\" value=\"down\">下载</button>" \
"</form>" \
"</body>" \
"</html>" \
""
};
struct espconn tcpserver;
uint8_t http_data[] = {
"HTTP/1.1 200 OK\r\n"\
"Content-Type:text/plain;charset=UTF-8\r\n"\
"Content-Disposition:attachment;\r\n"\
"\r\n"\
"get data"\
"\r\n"
};
void ICACHE_FLASH_ATTR
tcpserver_recon_cb(void *arg, sint8 errType)//异常断开回调
{
struct espconn *pespconn = (struct espconn *)arg;
os_printf("\r\n异常断开");
}
void ICACHE_FLASH_ATTR
tcpserver_discon_cb(void *arg)//正常断开回调
{
struct espconn *pespconn = (struct espconn *)arg;
os_printf("\r\n正常断开");
}
void ICACHE_FLASH_ATTR
tcpclient_sent_cb(void *arg)//发送回调
{
struct espconn *pespconn = (struct espconn *)arg;
espconn_disconnect(pespconn);//断开连接
os_printf("\r\n发送回调");
}
void ICACHE_FLASH_ATTR
void ICACHE_FLASH_ATTR
tcpserver_recv(void *arg, char *pdata, unsigned short len)//接收函数
{
char * http_flg = NULL;
unsigned short i,web_len = 0;
struct espconn *pespconn = (struct espconn *)arg;
os_printf("\r\n接收函数,%s",pdata);
http_flg = strstr(pdata,"btn=down");
if (http_flg != NULL) {
espconn_send(pespconn, http_data, sizeof(http_data));
} else {
webserver接口开发http_flg = strstr(pdata,"HTTP");
if(http_flg != NULL){
espconn_send(pespconn,http_head,sizeof(http_head));
}
}
}
void ICACHE_FLASH_ATTR
tcpserver_listen(void *arg)//服务器被链接回调
{
struct espconn *pespconn = (struct espconn *)arg;
espconn_regist_reconcb(pespconn, tcpserver_recon_cb);//开启异常断开回调 espconn_regist_disconcb(pespconn, tcpserver_discon_cb);//开启正常断开回调 espconn_regist_recvcb(pespconn, tcpserver_recv);//开启接收回调
espconn_regist_sentcb(pespconn, tcpclient_sent_cb);//开启发送成功回调
}
void ICACHE_FLASH_ATTR
tcp_server(void)//开启tcp服务器
{
p = (esp_tcp *)os_zalloc(sizeof(esp_tcp));
p->local_port = 80;//监听本地端⼝号
tcpserver.state = ESPCONN_NONE;
espconn_regist_connectcb(&tcpserver, tcpserver_listen);//链接成功回调
espconn_accept(&tcpserver);//开启TCP服务器
espconn_regist_time(&tcpserver, 1, 0);//设置服务器超时时间为1秒
}
把user_main.c全部改为下⾯的代码。
#include "ets_sys.h"
#include "osapi.h"
#include "user_interface.h"
#include "user_devicefind.h"
#include "user_webserver.h"
#include "driver/uart.h"
#if ESP_PLATFORM
#include "user_esp_platform.h"
#endif
uint32 priv_param_start_sec;
struct softap_config softap_cfg;
uint8 ssid[]="esp8266_wifi";        //wifi名
uint8 password[]="12345678";    //wifi密码
void ICACHE_FLASH_ATTR
user_set_softap_config(void)
{
wifi_softap_get_config(&softap_cfg); // Get config first.
wifi_set_opmode(SOFTAP_MODE);          //设置为AP MODE
os_strcpy(softap_cfg.ssid, ssid);          //ssid名称
os_strcpy(softap_cfg.password, password);  //密码
softap_cfg.authmode = AUTH_WPA_WPA2_PSK;
softap_cfg.ssid_len = 0; // or its actual length
softap_cfg.max_connection = 4; // how many stations can connect to ESP8266 softAP at most.    wifi_softap_set_config(&softap_cfg);      //设置WIFI帐号和密码
}
/******************************************************************************
* FunctionName : user_rf_cal_sector_set
* Description  : SDK just reversed 4 sectors, used for rf init data and paramters.
*                We add this function to force users to set rf cal sector, since
*                we don't know which sector is free in user's application.
*                sector map for last several sectors : ABCCC
*                A : rf cal
*                B : rf init data
*                C : sdk parameters
* Parameters  : none
* Returns      : rf cal sector
*******************************************************************************/
uint32 ICACHE_FLASH_ATTR
user_rf_cal_sector_set(void)
{
enum flash_size_map size_map = system_get_flash_size_map();
uint32 rf_cal_sec = 0;
switch (size_map) {
case FLASH_SIZE_4M_MAP_256_256:
rf_cal_sec = 128 - 5;
priv_param_start_sec = 0x3C;
break;
case FLASH_SIZE_8M_MAP_512_512:
rf_cal_sec = 256 - 5;
priv_param_start_sec = 0x7C;
break;
case FLASH_SIZE_16M_MAP_512_512:
rf_cal_sec = 512 - 5;
priv_param_start_sec = 0x7C;
break;
case FLASH_SIZE_16M_MAP_1024_1024:
rf_cal_sec = 512 - 5;
priv_param_start_sec = 0xFC;
break;
case FLASH_SIZE_32M_MAP_512_512:
rf_cal_sec = 1024 - 5;
priv_param_start_sec = 0x7C;
break;
case FLASH_SIZE_32M_MAP_1024_1024:
rf_cal_sec = 1024 - 5;
priv_param_start_sec = 0xFC;
break;
case FLASH_SIZE_64M_MAP_1024_1024:
rf_cal_sec = 2048 - 5;
priv_param_start_sec = 0xFC;
break;
case FLASH_SIZE_128M_MAP_1024_1024:
rf_cal_sec = 4096 - 5;
priv_param_start_sec = 0xFC;
break;
default:
rf_cal_sec = 0;
priv_param_start_sec = 0;
break;
}
return rf_cal_sec;
}
void ICACHE_FLASH_ATTR
user_rf_pre_init(void)
{
}
void esp_init_ok(void)
{
uart0_sendStr("Hello Esp8266!\r\n");
tcp_server();//开启tcp服务器
}
/******************************************************************************
* FunctionName : user_init
* Description  : entry of user application, init user function here
* Parameters  : none
* Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
user_init(void)
{
uart_init(BIT_RATE_115200,BIT_RATE_115200);
user_set_softap_config();  //set STATION config
system_init_done_cb(esp_init_ok);
#ifdef SERVER_SSL_ENABLE
user_webserver_init(SERVER_SSL_PORT);
#else
//    user_webserver_init(SERVER_PORT);
#endif
}
这样,就实现带密码的WiFi热点,在浏览器打开192.168.4.1即可看到⽹页,点击下载按钮能下载到⼀个txt⽂件。苹果⼿机由于权限问题不能下载到txt,安卓⼿机可以下载到txt。
四、其它问题。
1、如何写⽹页?
下载⼀个来编写你的⽹页。
然后使⽤⼩⼯具把html语⾔转成c语⾔,,这个⼩⼯具转换出来的C语⾔可能出错,⾃⼰检测⼀下转义字符就可以了。