ESP8266可以方便的进行UDP通讯实现通过网络控制设备的功能,但是该方法对于用户来说还需要一个界面来完成数据通讯,所幸ESP系列有着不错的性能和不小的存储空间,足够用来构建简单的网页服务器(Web Server),这样用户就可以通过浏览器访问进行查看数据或控制设备。
这篇文章中更多的会涉及一些底层原理相关的内容,想要简单的使用可以参考《从零开始的ESP8266探索(09)-更加方便的ESP8266WebServer使用介绍》
如果你只是想要用TCP Server功能那也可以参考下面内容。
在Arduino for esp8266中启用服务功能非常简单,如下两步即可实现:
WiFiServer server(80); //建立服务器对象,设置监听端口号为80(网页默认端口号)
server.begin(); //启用服务器
只要上述两步就完成了Server的设置,接下来就是具体的处理工作了。
Server的具体处理事务在loop()函数中进行,首先请看下述代码:
String readString = ""; //建立一个字符串对象用来接收存放来自客户的数据
void loop()
{
WiFiClient client = server.available(); //尝试建立客户对象
if (client) //如果当前有客户可用
{
boolean currentLineIsBlank = true;
Serial.println("[Client connected]");
while (client.connected()) //如果客户端建立连接
{
if (client.available()) //等待有可读数据
{
char c = client.read(); //读取一字节数据
readString += c; //拼接数据
/************************************************/
if (c == '\n' && currentLineIsBlank) //等待请求头接收完成(接收到空行)
{
break;
}
if (c == '\n')
{
currentLineIsBlank = true; //开始新行
}
else if (c != '\r')
{
currentLineIsBlank = false; //正在接收某行中
}
/************************************************/
}
}
delay(1); //等待客户完成接收
client.stop(); //结束当前连接:
Serial.println("[Client disconnected]");
Serial.println(readString); //打印输出来自客户的数据
readString = "";
}
}
以上代码中除去/***/
和/***/
之间部分代码为监听客户端连接并接收数据功能;/***/
和/***/
之间部分代码用于对客户端的请求进行处理。将代码烧录到模块中进行测试,可以看到效果如下:
可以看到在浏览器访问Server的时候Server会接收到下面的信息:
GET / HTTP/1.1
Accept: text/html, application/xhtml+xml, image/jxr, /
Accept-Language: zh-Hans-CN,zh-Hans;q=0.8,ja;q=0.6,en-US;q=0.4,en;q=0.2
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: 172.16.2.231
Connection: Keep-Alive
(还有一种GET /favicon.ico HTTP/1.1开头的,是请求图标的)
这个信息就是浏览器向Server发出的信息,到目前为止这只是一个标准的TCP Server,如果我们在收到浏览器发送的信息后做出对应的应答(HTTP协议),那这就变成了Web Server。
上面的测试中浏览器发出的消息是什么,应该怎么处理,了解的这些就能完成完整的Web Server功能了,该部分内容可以参考如下:
根据上文内容综合可知,对于Web Server来说只要接收到完整的请求头时返回相应的东西即可,更改上面部分代码我们的Web Server基本功能就实现了:
首先准备好响应头
和网页
:
//响应头
String responseHeaders =
String("") +
"HTTP/1.1 200 OK\r\n" +
"Content-Type: text/html\r\n" +
"Connection: close\r\n" +
"\r\n";
//网页
String myhtmlPage =
String("") +
"Hello World";
然后上文中代码改写如下:
if (c == '\n' && currentLineIsBlank) //等待请求头接收完成(接收到空行)
{
//比较接收到的请求数据
if (readString.startsWith("GET / HTTP/1.1")) //如果是网页请求
{
client.print(responseHeaders); //向客户端输出网页响应
client.print(myhtmlPage); //向客户端输出网页内容
client.print("\r\n");
}
else
{
client.print("\r\n");
}
break;
}
上述代码烧录运行后可以看到下面请,在浏览器访问时可以看到我们准备的网页内容:
上面内容其实已经完成了基本的Web Server功能,现在我们再进一步,实现网页和服务器的数据交互功能,在这里需要用到AJAX知识,很简单,可以参考下面的教程:
http://www.w3school.com.cn/ajax/
http://www.runoob.com/ajax/ajax-tutorial.html
在下文中我们将要实现通过浏览器访问建立于ESP8266上的网页,网页中显示ESP8266模块上LED状态和一个按钮,通过点击按钮可以点亮/熄灭LED。
首先我们准备一个网页:
<html>
<head>
<title>ESP8266 Web Server Testtitle>
<script defer="defer">
function ledSwitch() {
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
} else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
document.getElementById("txtState").innerHTML = xmlhttp.responseText;
}
},
xmlhttp.open("GET", "Switch", true);
xmlhttp.send();
}
script>
head>
<body>
<div id="txtState">Unkwondiv>
<input type="button" value="Switch" onclick="ledSwitch()">
body>
html>
网页初始效果如下:
网页可以通过以下网站转成字符串:
http://www.css88.com/tool/html2js/
下面是完整的需要烧录到ESP8266中的代码:
#include
/*** 该工程可以在2.4.0版本esp8266库中运行,没在更高版本库中进行测试 ***/
const char *ssid = "********";
const char *password = "********";
WiFiServer server(80);
String readString = ""; //建立一个字符串对象用来接收存放来自客户的数据
//响应头
String responseHeaders =
String("") +
"HTTP/1.1 200 OK\r\n" +
"Content-Type: text/html\r\n" +
"Connection: close\r\n" +
"\r\n";
//网页
String myhtmlPage =
String("") +
"" +
"" +
" ESP8266 Web Server Test " +
" " +
"" +
"" +
" Unkwon" +
" " +
"" +
"";
bool isLedTurnOpen = false; // 记录LED状态
void setup()
{
pinMode(2, OUTPUT);
digitalWrite(2, HIGH); // 熄灭LED
Serial.begin(115200);
Serial.println();
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println(" connected");
server.begin();
Serial.printf("Web server started, open %s in a web browser\n", WiFi.localIP().toString().c_str());
}
void loop()
{
WiFiClient client = server.available(); //尝试建立客户对象
if (client) //如果当前有客户可用
{
boolean currentLineIsBlank = true;
Serial.println("[Client connected]");
while (client.connected()) //如果客户端建立连接
{
if (client.available()) //等待有可读数据
{
char c = client.read(); //读取一字节数据
readString += c; //拼接数据
/************************************************/
if (c == '\n' && currentLineIsBlank) //等待请求头接收完成(接收到空行)
{
//比较接收到的请求数据
if (readString.startsWith("GET / HTTP/1.1")) //如果是网页请求
{
client.print(responseHeaders); //向客户端输出网页响应
client.print(myhtmlPage); //向客户端输出网页内容
client.print("\r\n");
}
else if (readString.startsWith("GET /Switch")) //如果是改变LED状态请求
{
if (isLedTurnOpen == false)
{
digitalWrite(2, LOW); // 点亮LED
client.print("LED has been turn on");
isLedTurnOpen = true;
}
else
{
digitalWrite(2, HIGH); // 熄灭LED
client.print("LED has been turn off");
isLedTurnOpen = false;
}
}
else
{
client.print("\r\n");
}
break;
}
if (c == '\n')
{
currentLineIsBlank = true; //开始新行
}
else if (c != '\r')
{
currentLineIsBlank = false; //正在接收某行中
}
/************************************************/
}
}
delay(1); //等待客户完成接收
client.stop(); //结束当前连接:
Serial.println("[Client disconnected]");
Serial.println(readString); //打印输出来自客户的数据
readString = "";
}
}
将上面代码烧录运行可以看到下面效果:
使用Arduino for esp8266可以非常简单实现Web Server功能,更多详细内容可以参考如下:
Server功能示例:
https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/server-examples.html
Server功能库说明:
https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/server-class.html
这篇文章中更多的会涉及一些底层原理相关的内容,想要简单的使用可以参考《从零开始的ESP8266探索(09)-更加方便的ESP8266WebServer使用介绍》