Итак, я использую библиотеки ESP8266WebServer и ESP8266WiFiMulti для запуска веб-страницы с вебсокетами и пытаюсь выяснить, сколько клиентских подключений я может иметь, и есть ли способ увеличить этот лимит подключений?
Прямо сейчас кажется, что я могу успешно создать три соединения с отдельных IP-адресов, а затем при инициировании четвертого соединения оно не работает (сервер не не падает в последовательной модели, но четвертое соединение не загружает веб-страницу).
Я также заметил, что если я обновлю собственное одиночное соединение определенное количество раз (непостоянно), веб-страница также не загрузится. Я не смог понять, связано ли это с наличием слишком большого количества последовательных подключений в целом или с тем, что я перегружаю сервер, пытаясь повторно подключиться внутри слишком быстрый срок?
Однако в целом он кажется довольно нестабильным, и мне действительно не помешала бы помощь в выяснении причин.
Вот мой текущий код:
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WebSocketsServer.h>
#include <Hash.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
static const char ssid[] = "********";
static const char password[] = "********";
MDNSResponder mdns;
static void writeLED(bool);
ESP8266WiFiMulti WiFiMulti;
IPAddress ipAddressTest = (99,99,99,99);
ESP8266WebServer server(80);
WebSocketsServer webSocket = WebSocketsServer(81);
uint8_t pageHitCounter = 0;
IPAddress ipAddressOne = (99,99,99,99);
IPAddress ipAddressTwo = (99,99,99,99);
IPAddress ipAddressThree = (99,99,99,99);
IPAddress ipAddressFour = (99,99,99,99);
uint8_t rxBuff[256];
uint8_t som = 0x11;
uint8_t eom = 0x12;
uint8_t subsys;
uint8_t receivedSubsys;
uint8_t rx_byte = 0x00;
uint8_t messageLength = 0;
uint8_t receivedMessageLength = 0;
uint8_t messageContent;
uint8_t serialCurrent;
int initialCounter = 0;
boolean messageBegun = false;
boolean messageInProgress = false;
int currNumRefresh = 0;
int currMicroC = 0;
int currMicroD = 0;
int currMicroE = 0;
int currPressureC = 0;
int currPressureD = 0;
int currPressureE = 0;
int currValveStatusNumC = 0;
int currValveStatusNumD = 0;
int currValveStatusNumE = 0;
int currFluid = 0;
char statusbuf[256];
char status[] = "";
int statusIndex = 0;
String valveStatusC = "Closed";
String valveTubePropsC = "175px solid #00ADEF";
String valveColorC = "red";
String valveStatusD = "Closed";
String valveTubePropsD = "175px solid #00ADEF";
String valveColorD = "red";
String valveStatusE = "Closed";
String valveTubePropsE = "175px solid #00ADEF";
String valveColorE = "red";
uint8_t currCountdown = 0;
long prevTimeCountdown = 0;
long countdownInterval = 1000;
long countdownPostInterval = 100;
bool countdownFlag = true;
bool teensyPOWER = false;
bool pumpPOWER = false;
bool teensyLED = false;
void switchPOWERon() {
//Serial.println("TEST POWER ON");
int powerStatusLength = 1;
subsys = 0x10;
//Account for the end of message
messageLength = powerStatusLength + 2;
messageContent = 1;
Serial.write(som);
Serial.write(messageLength);
Serial.write(subsys);
Serial.write(messageContent);
Serial.write(eom);
//Serial.println("");
//Serial.println("TURN POWER ON|");
//teensyLED = true;
} //end switchPOWERon
void switchPOWERoff() {
/*Very similar to switchPoweron(), removed for char space*/
} //end switchPOWERoff
void pumpPOWERon() {
//Serial.println("TEST POWER ON");
int pumpPowerStatusLength = 1;
subsys = 0x13;
//Account for the end of message
messageLength = pumpPowerStatusLength + 2;
messageContent = 1;
Serial.write(som);
Serial.write(messageLength);
Serial.write(subsys);
Serial.write(messageContent);
Serial.write(eom);
//Serial.println("");
//Serial.println("TURN POWER ON|");
//teensyLED = true;
} //end switchPOWERon
void pumpPOWERoff() {
/*Very similar to pumpPoweron(), removed for char space*/
} //end switchPOWERoff
void switchLEDon() {
//Serial.println("TEST LED ON");
int ledStatusLength = 1;
subsys = 0x14;
//Account for the end of message
messageLength = ledStatusLength + 2;
messageContent = 1;
Serial.write(som);
Serial.write(messageLength);
Serial.write(subsys);
Serial.write(messageContent);
Serial.write(eom);
//Serial.println("");
//Serial.println("TURN LED ON|");
//teensyLED = true;
} //end switchLEDon
void switchLEDoff() {
/*Very similar to switchLEDon(), removed for char space*/
} //end switchLEDoff
void statusUpdate(uint8_t num) {
//Valve C
if(currValveStatusNumC == 0)
{
valveColorC = "red";
valveTubePropsC = "175px solid #00ADEF";
valveStatusC = "Closed";
} //end if
else if(currValveStatusNumC == 1)
{
valveColorC = "green";
valveTubePropsC = "350px solid #00ADEF";
valveStatusC = "Open";
} //end else if
/*Valves D/E removed for char space, very similar to Valve C*/
String test = "";
test += currNumRefresh;
test += ",";
/*Preparing more variables to send to the webpage, removed for char space*/
test += ",";
test += ipAddressTest;
//Serial.print("TEST: ");
//Serial.println(ipAddressTest);
test.toCharArray(statusbuf, 256);
webSocket.sendTXT(num, statusbuf, strlen(statusbuf));
}
static const char PROGMEM INDEX_HTML[] = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<title>Adafruit HUZZAH ESP8266</title>
<style type='text/css'>
/*CSS removed to fit maximum number of allowed characters*/
</style>
<script>
var currPressureTest = 0;
var currFluidTest = 0;
function POWERswitch(){
var POWERswitchCheck = document.getElementById('switch1').checked;
if(POWERswitchCheck){
websock.send("teensyPOWERon");
}
else if(!POWERswitchCheck) {
websock.send("teensyPOWERoff");
}
}
function FLUSHbegin(){
websock.send("pumpPOWERon");
}
function FLUSHend(){
websock.send("pumpPOWERoff");
}
function LEDswitch(){
var LEDswitchCheck = document.getElementById('myonoffswitch').checked;
if(LEDswitchCheck){
websock.send("teensyLEDon");
}
else if(!LEDswitchCheck) {
websock.send("teensyLEDoff");
}
}
var websock;
var test = "open";
var webpageHitCounter = 20;
function start() {
websock = new WebSocket('ws://' + window.location.hostname + ':81/');
websock.onopen = function(evt) {
console.log('websock open');
statusUpdate();
};
websock.onclose = function(evt) {
console.log('websock close');
};
websock.onerror = function(evt) {
console.log(evt);
};
websock.onmessage = function(evt) {
console.log(evt);
var e = document.getElementById('ledstatus');
var te = document.getElementById('myonoffswitch');
var pe = document.getElementById('switch1');
if(evt.data === 'teensyPOWERon')
{
pe.checked = 'checked';
}
else if(evt.data === 'teensyPOWERoff')
{
pe.checked = '';
}
else if(evt.data === 'pumpPOWERon')
{
}
else if(evt.data === 'pumpPOWERoff')
{
}
else if(evt.data === 'teensyLEDon')
{
te.checked = 'checked';
}
else if(evt.data === 'teensyLEDoff')
{
te.checked = '';
}
else if(evt.data === 'Update Status')
{
}
else {
console.log('status event');
var totalStatus = evt.data;
var splitStatus = totalStatus.split(',');
//Num Refresh
document.getElementById("demo").innerHTML = splitStatus[0];
/*Setting more variables from splitStatus[], removed for char space*/
}
};
}
function statusUpdate() {
websock.send("Update Status");
setTimeout('statusUpdate()', 5000);
}
</script>
</head>
<body style='background-color:#4a4a4c;' onload="start();">
<div style='text-align:center;'>
<h1 style='text-decoration: underline; color:white;'>Adafruit HUZZAH ESP8266</h1>
</div>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<div style="clear:both;"></div>
<div class='counterContainer'>
<span id="counterText" style="color:white;"></span>
</div>
<div id='adminControls' class='adminControlsRow'>
<h2>Administrator Controls</h2>
<div id='Newbtn' class='powerSwitchContainer'>
<h2>HHIO PTT Power</h2>
<span class="switch">
<span class="switch-border1">
<span class="switch-border2">
<input id="switch1" type="checkbox" onclick='POWERswitch()' checked />
<label for="switch1"></label>
<span class="switch-top"></span>
<span class="switch-shadow"></span>
<span class="switch-handle"></span>
<span class="switch-handle-left"></span>
<span class="switch-handle-right"></span>
<span class="switch-handle-top"></span>
<span class="switch-handle-bottom"></span>
<span class="switch-handle-base"></span>
<span class="switch-led switch-led-green">
<span class="switch-led-border">
<span class="switch-led-light">
<span class="switch-led-glow"></span>
</span>
</span>
</span>
<span class="switch-led switch-led-red">
<span class="switch-led-border">
<span class="switch-led-light">
<span class="switch-led-glow"></span>
</span>
</span>
</span>
</span>
</span>
</span>
</div>
<div class='flushBtnContainer'>
<h2>Fluid Reservoir</h2>
<button id='flushBtn' onmousedown="FLUSHbegin();" onmouseup="FLUSHend();">Flush</button>
</div>
</div>
<div style='background-color:#1E1E20; clear:both;'>
<h2 style='color: white;'>LED Controls</h2>
<div id='LEDbtn' class='onoffswitch'>
<input type='checkbox' name='onoffswitch' class='onoffswitch-checkbox' id='myonoffswitch' onclick='LEDswitch()'>
<label class='onoffswitch-label' for='myonoffswitch'>
<span class='onoffswitch-inner'></span>
<span class='onoffswitch-switch'></span>
</label>
</div>
</div>
<div style='background-color:#1E1E20; color: white;'>
<h2>Num Refresh Test</h2>
<div id="demo"><h2>Let WEBSOCKET change this text</h2></div>
</div>
<div class='headerRow'>
/*Headers removed for char space*/
</div>
<div class='microswitchRow'>
<div class="microswitchContainer">
<div class="microswitch white">
<input type="radio" name="switchC" class="microswitchRadio" id="switchOffC" checked>
<input type="radio" name="switchC" class="microswitchRadio" id="switchOnC">
<label for="switchOffC">Detached</label>
<label for="switchOnC">Attached</label>
<span class="toggle"></span>
</div>
</div>
<div class="microswitchContainer">
<div class="microswitch white">
<input type="radio" name="switchD" class="microswitchRadio" id="switchOffD" checked>
<input type="radio" name="switchD" class="microswitchRadio" id="switchOnD">
<label for="switchOffD">Detached</label>
<label for="switchOnD">Attached</label>
<span class="toggle"></span>
</div>
</div>
<div class="microswitchContainer">
<div class="microswitch white">
<input type="radio" name="switchE" class="microswitchRadio" id="switchOffE" checked>
<input type="radio" name="switchE" class="microswitchRadio" id="switchOnE">
<label for="switchOffE">Detached</label>
<label for="switchOnE">Attached</label>
<span class="toggle"></span>
</div>
</div>
</div>
<div class='pressureRow'>
<div class='pressureContainer'>
<div class='gauge-a'></div>
<div class='gauge-b'></div>
<div class='gauge-c'></div>
<div class='gauge-data'><h1 id='pressurePercentC'>0%</h1></div>
</div>
<div class='pressureContainer'>
<div class='gauge-a'></div>
<div class='gauge-b'></div>
<div class='gauge-d'></div>
<div class='gauge-data'><h1 id='pressurePercentD'>0%</h1></div>
</div>
<div class='pressureContainer'>
<div class='gauge-a'></div>
<div class='gauge-b'></div>
<div class='gauge-e'></div>
<div class='gauge-data'><h1 id='pressurePercentE'>0%</h1></div>
</div>
</div>
<div class='valveRow'>
<div class='valveContainer'>
<div class="valveTube-c"></div>
<div class="valve-c"></div>
<div class='valve-data'><h1 id='valveStatus-c'>Closed</h1></div>
</div>
<div class='valveContainer'>
<div class="valveTube-d"></div>
<div class="valve-d"></div>
<div class='valve-data'><h1 id='valveStatus-d'>Closed</h1></div>
</div>
<div class='valveContainer'>
<div class="valveTube-e"></div>
<div class="valve-e"></div>
<div class='valve-data'><h1 id='valveStatus-e'>Closed</h1></div>
</div>
</div>
<div class='fluidContainer'>
<meter class='fluidMeter' max='100' value='50' low='25' high='75' optimum='100'></meter>
<div class='fluid-data'><h1 id='fluidPercent'>0%</h1></div>
</div>
</body>
</html>
)rawliteral";
const int LEDPIN = 0;
// Current POWER status
bool POWERStatus;
// Current LED status
bool LEDStatus;
// Commands sent through Web Socket
/*command array declarations removed for char space*/
const char statusIdentifier[] = "Update Status";
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length)
{
//Serial.printf("webSocketEvent(%d, %d, ...)\r\n", num, type);
switch(type) {
case WStype_DISCONNECTED:
//Serial.printf("[%u] Disconnected!\r\n", num);
break;
case WStype_CONNECTED:
{
IPAddress ip = webSocket.remoteIP(num);
//Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\r\n", num, ip[0], ip[1], ip[2], ip[3], payload);
// Send the current LED status
if (LEDStatus) {
webSocket.sendTXT(num, LEDON, strlen(LEDON));
}
else if(!LEDStatus) {
webSocket.sendTXT(num, LEDOFF, strlen(LEDOFF));
}
else if(teensyPOWER) {
webSocket.sendTXT(num, teensyPOWERON, strlen(teensyPOWERON));
}
else if(!teensyPOWER) {
webSocket.sendTXT(num, teensyPOWEROFF, strlen(teensyPOWEROFF));
}
else if(pumpPOWER) {
webSocket.sendTXT(num, teensyPOWERON, strlen(teensyPOWERON));
}
else if(!pumpPOWER) {
webSocket.sendTXT(num, pumpPOWEROFF, strlen(pumpPOWEROFF));
}
else if(teensyLED) {
webSocket.sendTXT(num, teensyLEDON, strlen(teensyLEDON));
}
else if(!teensyLED) {
webSocket.sendTXT(num, teensyLEDOFF, strlen(teensyLEDOFF));
}
}
break;
case WStype_TEXT:
//Serial.printf("[%u] get Text: %s\r\n", num, payload);
if (strcmp(LEDON, (const char *)payload) == 0) {
writeLED(true);
}
else if (strcmp(LEDOFF, (const char *)payload) == 0) {
writeLED(false);
}
else if(strcmp(teensyPOWERON, (const char *)payload) == 0) {
switchPOWERon();
}
else if(strcmp(teensyPOWEROFF, (const char *)payload) == 0) {
switchPOWERoff();
}
else if(strcmp(pumpPOWERON, (const char *)payload) == 0) {
pumpPOWERon();
}
else if(strcmp(pumpPOWEROFF, (const char *)payload) == 0) {
pumpPOWERoff();
}
else if(strcmp(teensyLEDON, (const char *)payload) == 0) {
switchLEDon();
}
else if(strcmp(teensyLEDOFF, (const char *)payload) == 0) {
switchLEDoff();
}
else if(strcmp(statusIdentifier, (const char *)payload) == 0) {
statusUpdate(num);
}
else {
//Serial.println("Unknown command");
}
// send data to all connected clients
webSocket.broadcastTXT(payload, length);
break;
case WStype_BIN:
//Serial.printf("[%u] get binary length: %u\r\n", num, length);
hexdump(payload, length);
// echo data back to browser
webSocket.sendBIN(num, payload, length);
break;
default:
//Serial.printf("Invalid WStype [%d]\r\n", type);
break;
}
}
void handleRoot()
{
server.send(200, "text/html", INDEX_HTML);
if(ipAddressTest != (0,0,0,0))
{
if(ipAddressOne == (99,99,99,99))
{
ipAddressOne = ipAddressTest;
pageHitCounter++;
//server.send(200, "text/html", INDEX_HTML);
Serial.print("1st NEW IP: ");
Serial.println(ipAddressTest);
}
else if(ipAddressTwo == (99,99,99,99))
{
if(ipAddressOne == ipAddressTest)
{
Serial.print("Old Connection-1 currently connected; Current Connection: ");
Serial.println(ipAddressTest);
//server.send(200, "text/html", INDEX_HTML);
}
else
{
ipAddressTwo = ipAddressTest;
pageHitCounter++;
//server.send(200, "text/html", INDEX_HTML);
Serial.print("2nd NEW IP: ");
Serial.println(ipAddressTest);
}
}
else if(ipAddressThree == (99,99,99,99))
{
if(ipAddressOne == ipAddressTest || ipAddressTwo == ipAddressTest)
{
Serial.print("Old Connection-2 currently connected; Current Connection: ");
Serial.println(ipAddressTest);
//server.send(200, "text/html", INDEX_HTML);
}
else
{
ipAddressThree = ipAddressTest;
pageHitCounter++;
//server.send(200, "text/html", INDEX_HTML);
Serial.print("3rd NEW IP: ");
Serial.println(ipAddressTest);
}
}
else if(ipAddressFour == (99,99,99,99))
{
if(ipAddressOne == ipAddressTest || ipAddressTwo == ipAddressTest || ipAddressThree == ipAddressTest)
{
Serial.println("Old Connection-3 currently connected; Current Connection: ");
Serial.println(ipAddressTest);
//server.send(200, "text/html", INDEX_HTML);
}
else
{
ipAddressFour = ipAddressTest;
pageHitCounter++;
//server.send(200, "text/html", INDEX_HTML);
Serial.print("4th NEW IP: ");
Serial.println(ipAddressTest);
}
}
else
{
if(ipAddressOne == ipAddressTest || ipAddressTwo == ipAddressTest || ipAddressThree == ipAddressTest || ipAddressFour == ipAddressTest)
{
Serial.println("Old Connection-4 currently connected; Current Connection: ");
Serial.println(ipAddressTest);
//server.send(200, "text/html", INDEX_HTML);
}
else
{
Serial.print("Too many connections! Attempting to Connect: ");
Serial.println(ipAddressTest);
}
}
}
}
void handleNotFound()
{
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET)?"GET":"POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i=0; i<server.args(); i++){
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
}
static void writeLED(bool LEDon)
{
LEDStatus = LEDon;
// Note inverted logic for Adafruit HUZZAH board
if (LEDon) {
digitalWrite(LEDPIN, 0);
}
else {
digitalWrite(LEDPIN, 1);
}
}
void setup()
{
pinMode(LEDPIN, OUTPUT);
writeLED(false);
Serial.begin(115200);
//Serial.setDebugOutput(true);
Serial.println();
Serial.println();
Serial.println();
currCountdown = 4;
for(uint8_t t = 4; t > 0; t--) {
unsigned long currTime = millis();
if(countdownFlag == true)
{
Serial.printf("[SETUP] BOOT WAIT %d...\r\n", t);
Serial.flush();
countdownFlag = false;
}
if(currTime - prevTimeCountdown > countdownInterval)
{
prevTimeCountdown = currTime;
countdownFlag = true;
} //end if
else
{
t++;
} //end else
} //end for
WiFiMulti.addAP(ssid, password);
/*
prevTimeCountdown = 0;
countdownFlag = true;
*/
while(WiFiMulti.run() != WL_CONNECTED) {
/*
unsigned long currTime = millis();
if(countdownFlag == true)
{
Serial.print(".");
countdownFlag = false;
} //end if
if(currTime - prevTimeCountdown > countdownInterval)
{
prevTimeCountdown = currTime;
countdownFlag = true;
} //end if
*/
Serial.print(".");
delay(1000);
} //end while
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
if (mdns.begin("espWebSock", WiFi.localIP())) {
Serial.println("MDNS responder started");
mdns.addService("http", "tcp", 80);
mdns.addService("ws", "tcp", 81);
}
else {
Serial.println("MDNS.begin failed");
}
Serial.print("Connect to http://espWebSock.local or http://");
Serial.println(WiFi.localIP());
server.on("/", handleRoot);
server.onNotFound(handleNotFound);
server.begin();
webSocket.begin();
webSocket.onEvent(webSocketEvent);
}
void loop()
{
//Communication Protocol
if(Serial.available() > 0)
{
//Serial.print("SERIAL.AVAILABLE: ");
//Serial.println(Serial.available());
if(initialCounter == 0)
{
rx_byte = Serial.read();
/*
//Print Start of Message
Serial.print("0x");
if(rx_byte<0x10)
{
Serial.print("0");
}
Serial.println(rx_byte, HEX);
*/
//Serial.println(rx_byte, BIN);
//Serial.println(rx_byte);
initialCounter++;
}
if((!messageBegun) && (rx_byte == som))
{
messageBegun = true;
//Serial.println("MESSAGE BEGUN TRUE");
} //end if (messageInProgress && rx_byte)
if((messageBegun) && (!messageInProgress))
{
serialCurrent = Serial.available();
if(serialCurrent > 0)
{
receivedMessageLength = (uint8_t)Serial.read();
/*
Serial.print("MESSAGE LENGTH: ");
Serial.println(receivedMessageLength);
*/
messageBegun = false;
messageInProgress = true;
//Serial.println("MESSAGE IN PROGRESS TRUE");
} //end if (serialCurrent)
} //end if (messageBegun && messageInProgress)
if(messageInProgress)
{
serialCurrent = Serial.available();
if(serialCurrent >= receivedMessageLength)
{
Serial.readBytes(rxBuff, receivedMessageLength);
if((byte)rxBuff[receivedMessageLength-1] != eom)
{
//Serial.println("ERROR");
//Serial.write(Serial.read());
} //end if (rxBuff != eom)
else
{
messageInProgress = false;
for(int i=0; i<receivedMessageLength; i++)
{
if(rxBuff[i] == eom)
{
/*
//Print End of Message
Serial.print("0x");
if(rx_byte<0x10)
{
Serial.print("0");
}
Serial.println(rxBuff[i], HEX);
*/
initialCounter = 0;
receivedMessageLength = 0;
} //end if
else if(i == 0)
{
receivedSubsys = rxBuff[i];
/*
//Print Subsystem
Serial.print("0x");
if(rx_byte<0x10)
{
Serial.print("0");
}
Serial.println(rxBuff[i], HEX);
*/
} //end if
else
{
if(receivedSubsys == 0x14)
{
currNumRefresh = rxBuff[i];
} //end if
/*Other subsystems removed for char space*/
} //end else
} //end if (serialCurrent)
} //end if (messageInProgress)
} //end if (Serial.available)
webSocket.loop();
ipAddressTest = server.handleClient();
}
P.S. Я немного изменил функцию handleClient() в ESP8266WebServer.cpp, чтобы она возвращала текущий IP-адрес для отслеживания отдельных пользователей, однако иногда я получаю 0.0.0.0 в качестве IP-адреса, и я не знаю, почему и как определить, является ли этот IP новым IP или нет.