参考教程:https://www.bilibili.com/video/BV1L7411c7jw/?spm_id_from=333.1387.favlist.content.click
七、ESP8266作为网络客户端
1、ESP8266作为网络客户端的行为
(1)网络客户端有很多种类型,像日常生活中使用的手机、电脑,以及ESP866-NodeMCU开发板,都可以作为网络客户端,向服务器发出请求。
(2)如果ESP866-NodeMCU作为客户端,接入一个与互联网连接的Wi-Fi网络中,那么ESP866-NodeMCU想要访问其它服务器的网站首页,大致流程如下所示。

2、使用ESP8266HTTPClient库实现网络通讯
(1)HTTPClient类是使用HTTP协议的网络客户端的抽象,该类的成员函数有如下几个(包括但不限于):
①begin函数:初始化HTTP请求并设置目标地址(URL,请求路径),并返回设置结果,True表示准备就绪,False表示URL格式错误或内存不足。
该函数有多种重载形式,最常用的是只有一个参数的重载形式,参数为指定URL的字符串类型数据
②GET函数:使用GET方法发送HTTP请求,并返回服务器响应的状态码,该函数无参数。
③POST函数:使用POST方法发送HTTP请求,并返回服务器响应的状态码,该函数无参数。
④getString函数:获取服务器HTTP响应报文中响应体的内容,以字符串的形式返回,该函数无参数。
⑤end函数:关闭ESP8266与服务器的连接,该函数无参数。
(2)使用ESP8266连接外部服务器,请求网址"http://www.example.com"的信息,其程序流程如下图所示。

(3)将以下示例程序粘贴到代码区中,然后将其编译并上传NodeMCU开发板,这样即可请求网址"http://www.example.com"的信息,并将返回的内容打印在串口监视器中。
cpp
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#define URL "http://www.example.com" //测试HTTP请求用的URL,注意网址前面必须添加"http://"
void setup() {
Serial.begin(9600);
WiFi.mode(WIFI_STA); //设置ESP8266工作模式为无线终端模式
WiFi.begin("Zevalin_Computer", "00114514"); //连接Wi-Fi
//等待Wi-Fi连接
while(WiFi.status() != WL_CONNECTED){
delay(1000);
Serial.print(".");
}
Serial.println("");
Serial.print("WiFi Connected!");
httpClientRequest(); //发送HTTP请求
}
void loop(){
}
//发送HTTP请求并且将服务器响应通过串口输出
void httpClientRequest(){
//创建 HTTPClient 对象
HTTPClient httpClient;
//通过begin函数配置请求地址
httpClient.begin(URL);
Serial.print("URL: "); Serial.println(URL);
//通过GET函数启动连接并发送HTTP请求
int httpCode = httpClient.GET();
Serial.print("Send GET request to URL: ");
Serial.println(URL);
//如果服务器响应HTTP_CODE_OK(200),则从服务器获取响应体信息并通过串口输出
//如果服务器不响应HTTP_CODE_OK(200),则将服务器响应状态码通过串口输出
if (httpCode == HTTP_CODE_OK) {
// 使用getString函数获取服务器响应体内容
String responsePayload = httpClient.getString();
Serial.println("Server Response Payload: ");
Serial.println(responsePayload);
}
else {
Serial.println("Server Respose Code:");
Serial.println(httpCode);
}
//关闭ESP8266与服务器连接
httpClient.end();
}
①WiFi.mode(val):配置ESP8266以val参数指定的模式工作,val的可选项有WIFI_OFF(关闭Wi-Fi)、WIFI_STA(无线终端模式)、WIFI_AP(接入点模式)、WIFI_AP_STA(接入点-无线终端双模式)。
②WiFi.begin(ssid, password):控制ESP8266接入Wi-Fi网络,其中ssid参数为Wi-Fi网络名,password为Wi-Fi网络密码。
3、使用WiFiClient库实现网络通讯
(1)WiFiClient类是使用Wi-Fi接入互联网的网络客户端的抽象,它比HTTPClient类的局限性更小(也就是不局限于使用HTTP协议),该类的成员函数有如下几个(包括但不限于):
①print函数:向服务器发送HTTP请求报文,函数参数为字符串类型的报文内容,报文内容需要程序员按照通信协议的格式自行构建(下图所示的是HTTP请求报文格式,CLRF为换行符)。

②connect函数:与服务器建立连接,第一个参数为被连接网络服务器的网址,第二个参数为被连接网络服务器的端口编号(HTTP协议的熟知端口号为80)。
③connected函数:如果ESP8266已与服务器建立连接,则返回True,否则返回False,该函数无参数。
④available函数:如果ESP8266接收到服务器返回的响应信息,则返回True,否则返回False,该函数无参数。
⑤readStringUntil函数:获取服务器返回的响应信息,直到遇到指定字符,返回字符串类型数据,该指定字符即为函数参数。
⑥find函数:获取服务器返回的响应信息,判断响应信息中有没有指定字符串,该指定字符串即为函数参数,有指定字符串则返回True,否则返回False。
(2)使用ESP8266连接外部服务器,请求网址"http://www.example.com"的信息,其程序流程如下图所示。

(3)将以下示例程序粘贴到代码区中,然后将其编译并上传NodeMCU开发板,这样即可请求网址"http://www.example.com"的信息,并将返回的内容打印在串口监视器中。
cpp
#include <ESP8266WiFi.h>
const char* host = "www.example.com"; // 目标网络服务器地址
const int httpPort = 80; // http熟知端口号
void setup(){
Serial.begin(9600);
Serial.println("");
WiFi.mode(WIFI_STA); //设置ESP8266工作模式为无线终端模式
WiFi.begin("Zevalin_Computer", "00114514"); //连接Wi-Fi
//等待Wi-Fi连接
while(WiFi.status() != WL_CONNECTED){
delay(1000);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi Connected!");
wifiClientRequest();
}
void loop(){
}
// 向服务器发送HTTP请求
void wifiClientRequest(){
// 建立Wi-Fi客户端对象,对象名称client
WiFiClient client;
// 建立字符串,用于HTTP请求(注意请求行和请求头的格式)
String httpRequest = String("GET /") + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n" +
"\r\n";
// 通过串口输出连接服务器名称,以便查阅连接服务器的网址
Serial.print("Connecting to ");
Serial.print(host);
// 连接网络服务器
if(client.connect(host, httpPort)){
Serial.println(" Success!"); // 连接成功后串口输出"Success"信息
client.print(httpRequest); // 向服务器发送HTTP请求
Serial.println("Sending request: ");// 通过串口输出HTTP请求信息内容
Serial.println(httpRequest);
// 通过串口输出网络服务器响应信息
Serial.println("Web Server Response:");
while (client.connected() || client.available()){
if (client.available()){
String line = client.readStringUntil('\n');
Serial.println(line);
}
}
client.stop(); // 断开与服务器的连接
Serial.print("Disconnected from "); // 通过串口输出断开连接信息
Serial.print(host);
}
else{
Serial.println(" connection failed!"); // 如果连接不成功,则通过串口输出"连接失败"信息
client.stop();
}
}
八、ESP8266 HTTP协议数据通讯
1、客户端向服务器发送数据信息
(1)在这个示例中,两块ESP8266连接同一个Wi-Fi网络,一块作为服务器,另一块作为客户端,ESP8266客户端将会通过HTTP协议向ESP8266服务器发送信息,最终实现的效果是,通过客户端ESP8266开发板上的按键来"遥控"服务器上的LED点亮和熄灭。
①在运行过程中,客户端ESP8266将会实时检测板上的按键状态,并且把按键状态发送给服务器。
②服务器在接收到客户端按键状态后,可以根据客户端按键状态来控制服务器端板上的LED点亮和熄灭。

(2)服务器端程序:
①程序任务:
1接收客户端发来的HTTP请求并且解析信息中的数据信息。
2将解析的数据信息通过串口监视器显示供用户查看。
3将解析的客户端按键状态信息用于控制服务器端板上LED的点亮和熄灭。
②程序框图:

③程序代码:
cpp
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h> // 使用WiFiMulti库
#include <ESP8266WebServer.h> // 使用WebServer库
ESP8266WiFiMulti wifiMulti; // 建立ESP8266WiFiMulti对象,对象名称是 'wifiMulti'
ESP8266WebServer server(80); // 建立网络服务器对象,该对象用于响应HTTP请求
IPAddress local_IP(192, 168, 10, 135); // ESP8266-NodeMCU联网后的IP
IPAddress gateway(192, 168, 10, 1); // 网关IP(通常网关IP是WiFI路由IP)
IPAddress subnet(255, 255, 255, 0); // 子网掩码
IPAddress dns(192, 168, 10, 1); // 局域网DNS的IP(通常局域网DNS的IP是Wi-FI路由的IP)
void setup(void){
Serial.begin(9600); // 启动串口通讯
Serial.println("");
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
// 设置开发板网络环境(配置开发板、网关的IP地址及子网掩码,局域网DNS的IP可选,非必须配置)
if(!WiFi.config(local_IP, gateway, subnet)) {
Serial.println("Failed to Config ESP8266 IP");
}
wifiMulti.addAP("Zevalin_Computer", "00114514");
wifiMulti.addAP("Zevalin_esp8266", "00114514");
Serial.println("Connecting ...");
while (wifiMulti.run() != WL_CONNECTED) {
delay(250);
Serial.print('.');
}
Serial.println('\n');
Serial.print("Connected to "); Serial.println(WiFi.SSID());
Serial.print("IP address:\t"); Serial.println(WiFi.localIP());
server.on("/update", handleUpdate); // 配置处理"/update"请求的函数
server.begin(); // 启动网站服务
Serial.println("HTTP server started");
}
void loop(void){
server.handleClient(); // 检查http服务器访问
}
void handleUpdate(){
float floatValue = server.arg("float").toFloat(); // 获取客户端发送HTTP信息中的浮点数值
int intValue = server.arg("int").toInt(); // 获取客户端发送HTTP信息中的整数数值
int buttonValue = server.arg("button").toInt(); // 获取客户端发送HTTP信息中的按键控制量
server.send(200, "text/plain", "Received"); // 发送http响应
buttonValue == 0 ? digitalWrite(LED_BUILTIN, LOW) : digitalWrite(LED_BUILTIN, HIGH);
// 通过串口监视器输出获取到的变量数值
Serial.print("floatValue = "); Serial.println(floatValue);
Serial.print("intValue = "); Serial.println(intValue);
Serial.print("buttonValue = "); Serial.println(buttonValue);
Serial.println("=================");
}
1IPAddress是类对IP地址的抽象,创建IPAddress类时,构造函数的参数为IP地址各组的数值,其中每8位为一组(IPv4)。
2WiFi.config函数用于配置开发板、网关的IP地址及子网掩码,局域网DNS的IP地址是可选参数,非必须配置。
(3)客户端程序:
①程序任务:
1客户端通过HTTP协议向服务器发送信息。
2信息中包含客户端按键开关引脚状态,用于控制服务器板上LED的点亮和熄灭。
3信息中包含测试数据。
②程序框图:

③程序代码:
cpp
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h> // 使用WiFiMulti库
#define buttonPin D3 // 按钮引脚D3
ESP8266WiFiMulti wifiMulti; // 建立ESP8266WiFiMulti对象,对象名称是 'wifiMulti'
bool buttonState; // 存储客户端按键控制数据
float clientFloatValue; // 存储客户端发送的浮点型测试数据
int clientIntValue; // 存储客户端发送的整数型测试数据
const char* host = "192.168.10.135"; // 即将连接服务器的网址/IP地址
const int httpPort = 80; // 即将连接服务器的端口
void setup(void){
Serial.begin(9600);
Serial.println("");
pinMode(buttonPin, INPUT_PULLUP); // 将按键引脚设置为输入上拉模式
wifiMulti.addAP("Zevalin_Computer", "00114514");
wifiMulti.addAP("Zevalin_esp8266", "00114514");
Serial.println("Connecting ...");
while(wifiMulti.run() != WL_CONNECTED){
delay(250);
Serial.print('.');
}
Serial.println('\n');
Serial.print("Connected to "); Serial.println(WiFi.SSID());
Serial.print("IP address:\t"); Serial.println(WiFi.localIP());
}
void loop(void){
// 获取按键引脚状态
buttonState = digitalRead(buttonPin);
// 改变测试用变量数值用于服务器端接收数据检测
clientFloatValue += 1.5;
clientIntValue += 2;
// 向服务器发送请求
wifiClientRequest();
delay(1000);
}
void wifiClientRequest(){
WiFiClient client;
// 将需要发送的数据信息放入客户端请求
String url = "/update?float=" + String(clientFloatValue) +
"&int=" + String(clientIntValue) +
"&button=" + String(buttonState);
// 建立字符串,用于HTTP请求
String httpRequest = String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n" +
"\r\n";
Serial.print("Connecting to ");
Serial.print(host);
if (client.connect(host, httpPort)){
Serial.println(" Sucess");
client.print(httpRequest); // 向服务器发送HTTP请求
Serial.println("Sending request: "); // 通过串口输出HTTP请求信息内容
Serial.println(httpRequest);
}
else{
Serial.println(" failed"); //如果连接失败则串口输出信息告知用户
}
client.stop();
}