WebSocket
由于在HTTP协议中,服务器不能主动向设备推送信息。设备使用轮询的方式向服务器请求数据时会消耗大量的设备运行资源与网络资源,因此WebSocket协议诞生。 WebSocket协议是建立在运输层协议TCP上进行全双工通信的协议,可以实现设备与物联网协议之间的平等传输,即客户端可以主动向服务器发送请求,服务器也可以向客户端推送信息。
若使用WebSocket,先引入WebSocket库,这里以 Links2004/arduinoWebSockets 的WebSocket库为例。库作者GitHub: https://github.com/Links2004/arduinoWebSockets 引入方法:
打开Ardunio IDE
点击标题栏项目 --> 加载库 --> 管理库打开库管理器
搜索WebSockets,找到Markus Sattler版本的WebSockets库,点击安装
WebSockets事件类型
关键字描述WStype_ERRORWebSocket连接发生错误时触发WStype_DISCONNECTED客户端或服务端关闭连接时触发WStype_CONNECTED客户端连接到服务端时触发WStype_TEXT接收到文本数据时触发WStype_BIN接收到二进制数据时触发WStype_PINGPing和Pong是websocket里的心跳,用来保证客户端是在线的,服务端给客户端发送PING,客户端发送PONG来回应WStype_PONG
使用步骤
WebSocketsServer
使用WebSockets库前需要将ESP8266NodeMCU连接到WIFI网络,并使其工作在WIFI_STA模式
引入WebSocketsServer库
#include <WebSocketsServer.h>
初始化WebSocketsServer对象,并设置端口号为81
WebSocketsServer
server(81);
在setup函数中启动WebSocketsServer,并指定事件处理函数
server
.begin();
server
.onEvent([](uint8_t num
, WStype_t type
, uint8_t
* payload
, size_t length
){
if (type
== WStype_TEXT
) String data
= (char*)payload
;
});
在loop函数中添加server.loop();若服务器想要给客户端发送文本数据,则使用sendTXT方法
server
.sendTXT(num
, str
);
其中客户端编号是根据客户端连接服务端的先后顺序来编号的,若知道客户端IP地址,可以通过遍历server.remoteIP();获取,例如:
int8_t
get_num_from_ip(IPAddress ip_needed
) {
for(uint8_t i
= 0; i
< WEBSOCKETS_SERVER_CLIENT_MAX
; i
++) {
IPAddress ip
= server
.remoteIP(i
);
if(ip
== ip_needed
) {
return i
;
}
}
return -1
}
WebSocketsClient
引入WebSocketsClient库
#include <WebSocketsClient.h>
初始化WebSocketsClient对象
WebSocketsClient wsClient
;
在setup函数中启动WebSocketsClient,并指定事件处理函数
wsClient
.begin(remoteHost
, 81);
wsClient
.onEvent([](WStype_t type
, uint8_t
* payload
, size_t length
) {
if (type
== WStype_TEXT
) String data
= (char*)payload
;
});
在loop函数中添加wsClient.loop();若客户端想要给服务器发送文本数据,则使用sendTXT方法
wsClient
.sendTXT(str
);
使用WebSocket控制LED
在该例子中,将使用两块ESP8266NodeMCU开发板A与B,实现使用开发板A上的FLASH按钮控制开发板B的LED灯,同时使用开发板B上的FLASH按钮控制开发板A的LED灯。两块开发板连接同一WIFI网络,并使用WebSocket协议进行网络通信。
开发板A:服务端开发板代码
#include <ESP8266WiFi.h>
#include <WebSocketsServer.h>
const String ssid
= "";
const String passwd
= "";
IPAddress
host(192, 168, 2, 10);
IPAddress
gateway(192, 168, 2, 1);
IPAddress
netmask(255, 255, 255, 0);
WebSocketsServer
server(81);
int pressState
;
void setup() {
Serial
.begin(9600);
pinMode(0, INPUT
);
pinMode(LED_BUILTIN
, OUTPUT
);
WiFi
.mode(WIFI_STA
);
if (!WiFi
.config(host
, gateway
, netmask
)) {
Serial
.println("Can't config wifi.");
}
Serial
.println("Connecting to " + ssid
);
WiFi
.begin(ssid
, passwd
);
while (WiFi
.status() != WL_CONNECTED
) {
Serial
.print('.');
delay(100);
}
Serial
.println("");
Serial
.println("Connected to " + ssid
);
Serial
.print("Current ip address is ");
Serial
.println(WiFi
.localIP());
server
.begin();
server
.onEvent([](uint8_t num
, WStype_t type
, uint8_t
* payload
, size_t length
){
if (type
== WStype_CONNECTED
) {
Serial
.println("New connection!");
} else if (type
== WStype_DISCONNECTED
) {
Serial
.println("Close the connection.");
} else if (type
== WStype_TEXT
) {
String data
= (char*)payload
;
if(data
.substring(data
.indexOf("=") + 1) == "on") {
digitalWrite(LED_BUILTIN
, LOW
);
} else if (data
.substring(data
.indexOf("=") + 1) == "off") {
digitalWrite(LED_BUILTIN
, HIGH
);
}
}
});
}
int8_t
get_num_from_ip(IPAddress ip_needed
) {
for(uint8_t i
= 0; i
< WEBSOCKETS_SERVER_CLIENT_MAX
; i
++) {
IPAddress ip
= server
.remoteIP(i
);
if(ip
== ip_needed
) {
return i
;
}
}
return -1;
}
void loop() {
server
.loop();
if (digitalRead(0) != pressState
) {
pressState
= digitalRead(0);
String data
= String("ledStatus=") + (digitalRead(0) == HIGH
? "off": "on");
server
.sendTXT(get_num_from_ip(IPAddress(192, 168, 2, 8)), data
);
}
}
开发板B:客户端开发板代码
#include <ESP8266WiFi.h>
#include <WebSocketsClient.h>
const String ssid
= "";
const String passwd
= "";
IPAddress
host(192, 168, 2, 8);
IPAddress
gateway(192, 168, 2, 1);
IPAddress
netmask(255, 255, 255, 0);
String remoteHost
= "192.168.2.10";
WebSocketsClient wsClient
;
int pressState
;
void setup() {
Serial
.begin(9600);
pinMode(0, INPUT
);
pinMode(LED_BUILTIN
, OUTPUT
);
WiFi
.mode(WIFI_STA
);
if (!WiFi
.config(host
, gateway
, netmask
)) {
Serial
.println("Can't config wifi.");
}
Serial
.println("Connecting to " + ssid
);
WiFi
.begin(ssid
, passwd
);
while (WiFi
.status() != WL_CONNECTED
) {
Serial
.print('.');
delay(100);
}
Serial
.println("");
Serial
.println("Connected to " + ssid
);
Serial
.print("Current ip address is ");
Serial
.println(WiFi
.localIP());
wsClient
.begin(remoteHost
, 81);
wsClient
.onEvent([](WStype_t type
, uint8_t
* payload
, size_t length
) {
if (type
== WStype_TEXT
) {
String data
= (char*)payload
;
if(data
.substring(data
.indexOf("=") + 1) == "on") {
digitalWrite(LED_BUILTIN
, LOW
);
} else if (data
.substring(data
.indexOf("=") + 1) == "off") {
digitalWrite(LED_BUILTIN
, HIGH
);
}
}
});
}
void loop() {
wsClient
.loop();
if (digitalRead(0) != pressState
) {
pressState
= digitalRead(0);
String data
= String("ledStatus=") + (digitalRead(0) == HIGH
? "off": "on");
Serial
.println(data
);
wsClient
.sendTXT(data
);
}
}