Несколько клиентских серверов через Wi-Fi
Попытка настроить сервер на Arduino для поддержки нескольких клиентов, Я могу поддерживать один, но не хочу сбрасывать этот клиент, чтобы установить другое соединение.
#include <ESP8266WiFi.h>
const char* ssid = "your-ssid";
const char* password = "your-password";
// Создаем экземпляр сервера
// указываем порт для прослушивания в качестве аргумента
WiFiServer server(80);
void setup() {
Serial.begin(115200);
delay(10);
// подготавливаем GPIO2
pinMode(2, OUTPUT);
digitalWrite(2, 0);
// Подключаемся к сети Wi-Fi
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
// Запускаем сервер
server.begin();
Serial.println("Server started");
// Печатаем IP-адрес
Serial.println(WiFi.localIP());
}
void loop() {
// Проверяем, подключился ли клиент
WiFiClient client = server.available();
if (!client) {
return;
}
// Подождем, пока клиент отправит какие-то данные
Serial.println("new client");
while(!client.available()){
delay(1);
}
// Читаем первую строку запроса
String req = client.readStringUntil('\r');
Serial.println(req);
client.flush();
// Совпадение с запросом
int val;
if (req.indexOf("/gpio/0") != -1)
val = 0;
else if (req.indexOf("/gpio/1") != -1)
val = 1;
else {
Serial.println("invalid request");
client.stop();
return;
}
// Устанавливаем GPIO2 по запросу
digitalWrite(2, val);
client.flush();
// Подготовить ответ
String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIO is now ";
s += (val)?"high":"low";
s += "</html>\n";
// Отправляем ответ клиенту
client.print(s);
delay(1);
Serial.println("Client disonnected");
// Клиент действительно будет отключен
// когда функция возвращается и объект 'client' уничтожается
}
С помощью этого кода сервер одновременно обрабатывает только одного клиента, а мне нужно одновременно подключить несколько клиентов.
@user28203, 👍5
Обсуждение3 ответа
Вам необходимо отслеживать несколько WiFiClient
— например, объявить их массив, и каждый раз, когда server.available()
выдает новый, сохранить его в массиве.
Затем вам нужно убедиться, что ваш код не зависает в ожидании данных от каждого элемента. Вы можете обслуживать каждый WifiClient по очереди: если у него есть ожидающие данные (client[i].available()
равно true), прочитать данные (client[i].read()
) и сохраните его. Когда вы получаете \r
от клиента, вы знаете, что у вас есть целая строка, и вы можете ее обработать.
Вот почти полный (но непроверенный) пример, чтобы вы поняли, о чем я говорю. Естественно, это не единственный способ сделать это.
#include <ESP8266WiFi.h>
const char* ssid = "your-ssid";
const char* password = "your-password";
#define MAX_CLIENTS 10
#define MAX_LINE_LENGTH 50
// Создаем экземпляр сервера
// указываем порт для прослушивания в качестве аргумента
WiFiServer server(80);
WiFiClient *clients[MAX_CLIENTS] = { NULL };
char inputs[MAX_CLIENTS][MAX_LINE_LENGTH] = { 0 };
void setup() {
Serial.begin(115200);
delay(10);
// подготавливаем GPIO2
pinMode(2, OUTPUT);
digitalWrite(2, 0);
// Подключаемся к сети Wi-Fi
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
// Запускаем сервер
server.begin();
Serial.println("Server started");
// Печатаем IP-адрес
Serial.println(WiFi.localIP());
}
void loop() {
// Проверяем, подключился ли новый клиент
WiFiClient newClient = server.available();
if (client) {
Serial.println("new client");
// Находим первое неиспользуемое место
for (int i=0 ; i<MAX_CLIENTS ; ++i) {
if (NULL == clients[i]) {
clients[i] = new WiFiClient(newClient);
break;
}
}
}
// Проверяем, есть ли у каждого клиента данные
for (int i=0 ; i<MAX_CLIENTS ; ++i) {
// Если клиент используется и у него есть данные...
if (NULL != clients[i] && clients[i]->available() ) {
// Чтение данных
char newChar = clients[i]->read();
// Если у нас есть конец строки
// (Используя тест, который использует ваш код)
if ('\r' == newChar) {
// Бла-бла, делайте что хотите с input[i]
// Очистить строку для следующего раза
inputs[i][0] = NULL;
// Флеш, который был у вас в коде - не уверен
// зачем тебе это, а вот это
clients[i]->flush();
// Если вы хотите здесь отключить клиента, то сделайте так:
clients[i]->stop();
delete clients[i];
clients[i] = NULL;
} else {
// Добавляем его в строку
strcat(inputs[i], newChar);
// ВАЖНО: Ничто не мешает этому выйти за пределы строки и
// уничтожаем вашу память. Вы ДОЛЖНЫ остерегаться этого.
// Но я не собираюсь делать всю вашу работу за вас :-)
}
}
}
}
Должен ли я создать несколько серверов или несколько клиентов, @user28203
Нет — вы создаете один «WiFiServer», и он будет давать вам новый «WiFiClient» для каждого подключающегося клиента., @Mark Smith
Я создал массив клиентов, как использовать server.available с этим, @user28203
Знаете ли вы, как помещать элементы в массив в целом?, @Mark Smith
Создать_клиент (){, @user28203
интервал я=1; Create_client (){ Клиент WiFiClient [i]; я++;}, @user28203
Всякий раз, когда появляется новое соединение, я использую функцию create_client, @user28203
Как проверить, когда есть новое подключение и что доступно для server., @user28203
Хорошо, почти полный код добавлен. Он не проверен, поэтому я рекомендую вам прочитать его и попытаться понять, что он делает, а затем сделать это самостоятельно, а не пытаться запустить его как есть и найти все мои опечатки. Если это полезно, подумайте о том, чтобы принять ответ и проголосовать за него. Спасибо., @Mark Smith
Это следует принять как ответ, и, поскольку вопрос возникает так часто, его, вероятно, следует добавить во встроенные примеры Arduino IDE для WiFi101 и других подобных библиотек WiFi., @Craig.Feied
Я не уверен, что сохранение IP-адреса - это хороший способ.... Интернет — это не сеть с постоянным подключением. Таким образом, невозможно быть уверенным, что компьютер, использующий IP-адрес в одно время, через минуту будет тем же компьютером, просто потому, что он имеет тот же IP-адрес., @Peter
@Peter Должен ли этот комментарий быть под другим ответом?, @Mark Smith
Здесь я использовал массив WiFiClient. Причина в том, что указатель массива будет содержать предыдущие плюс последние WiFiClients (emoteIP и remotePort), и пользователь сможет выбрать, какой WIFiClient будет использоваться для связи.
Мы можем хранить IP-адрес, порт, а также весь объект WiFiClient в массиве
//========================================= "="
WebServer Wserver(80);
WiFiClient Wclient;
WiFiClient *Wificlients[10] = { NULL };
int Clientindex=-1;
Wclient = Wserver.client(); // или server.avilable(), если WiFiServer
Wificlients[Clientindex++]=new WiFiClient(Wclient);
int cntloggedinclient=0;
int kk=0;
while(Wificlients[kk] != NULL)
{
cntloggedinclient++; // Общее количество клиентов
kk++;
}
// Многоадресная рассылка байтов всем подключенным клиентам.
int kkk =0;
while(kkk<cntloggedinclient)
{
Wificlients[kkk]->write((unsigned char*) &newbuff,len);
kkk++;
}
Вы не можете полагаться на все данные, поступающие вместе - ваш цикл, который выполняет чтение дерева(), будет ненадежным. Вам нужно сохранить объект WiFiClient, если вы хотите иметь несколько подключений одновременно., @Mark Smith
У меня есть решение с использованием задач RTOS, я думаю, что это лучший способ управлять несколькими клиентами одновременно. Я тестирую этот код в модуле разработки ESP32.
#if CONFIG_FREERTOS_UNICORE
#define ARDUINO_RUNNING_CORE 0
#else
#define ARDUINO_RUNNING_CORE 1
#endif
#include <WiFi.h>
const char* ssid = "[YOUR-NETWORK-SSID]";
const char* password = "[YOUR-SSID-PASSWORD]";
void TaskClientSocket( void *pvParameters );
WiFiServer wifiServer(80);
void setup() {
// поместите сюда код установки для однократного запуска:
Serial.begin(115200);
delay(1000);
WiFi.begin(ssid,password);
Serial.println("Connecting to Wifi...");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("Connected to WiFi network");
Serial.println(WiFi.localIP());
wifiServer.begin();
}
void loop() {
WiFiClient client = wifiServer.available();
if( client){
Serial.println("New Client Connected...");
xTaskCreatePinnedToCore(
TaskClientSocket
, "TaskClientSocket"
, 4098
, &client
, 2
, NULL
, ARDUINO_RUNNING_CORE);
}
}
void TaskClientSocket( void *pvParameters )
{
WiFiClient clientHandle = *((WiFiClient*)pvParameters);
for (;;)
{
while(clientHandle.connected()){
while(clientHandle.available()>0){
char c = clientHandle.read();
clientHandle.write(c);
}
vTaskDelay(100);
}
clientHandle.stop();
Serial.println("Client disconnected");
vTaskDelete(NULL);
}
}
- Веб-сервер ESP8266 недоступен через 2 минуты после сброса
- Управление реле 5В с помощью Wemos D1 R1
- Постоянное отключение ESP8266 SocketIOclient с Python WebServerSocket
- Обновление сервера с помощью ESp8266 с нажатой кнопкой направления IN
- Как читать и записывать EEPROM в ESP8266
- Как исправить: Invalid conversion from 'const char*' to 'char*' [-fpermissive]
- ошибка: espcomm_upload_mem failed при загрузке скетча
- Как определить размер Flash?
Пожалуйста, опубликуйте код, который вы используете (минимальный полный проверяемый пример http://stackoverflow.com/help/mcve), и, возможно, кто-то вам поможет., @Mark Smith
Пожалуйста, уточните вашу конкретную проблему или добавьте дополнительные детали, чтобы выделить именно то, что вам нужно. Как сейчас написано, трудно точно сказать, о чем вы спрашиваете. См. страницу «Как спросить», чтобы получить помощь в разъяснении этого вопроса., @sa_leinad