Использование WiFiServer в режиме блокировки

Я изучаю сетевое программирование для ESP32 и начал с написания простого Telnet-сервера. Он использует объект WiFiServer для прослушивания порта 23 и просто записывает всё, что получает, в последовательный монитор.

Пример кода выглядит примерно так:

  // Прослушивание порта 23
  WiFiServer server(23);
  server.begin();

  // Цикл для обработки соединений
  while (true) {
    // Ожидание соединения
    WiFiClient client = server.available();
    if (client) {
      ...

Это работает нормально, но вызов server.available() неблокирующий, поэтому цикл выполняется непрерывно и использует 100% ресурсов процессора. На ПК я бы использовал сокет в блокирующем режиме, чтобы вызов accept() приостанавливал поток до тех пор, пока данные не станут доступны. Я делаю это, потому что 100% ресурсов процессора в многозадачной ОС — это довольно неэтично.

Мой вопрос: можно ли заставить функцию Server.available() вести себя подобно функции сокетов accept() и блокировать её до тех пор, пока соединение не станет доступным? Если нет, то что считается лучшим решением? Просто дать процессору работать на 100% или есть более эффективный способ написать код? Может быть, просто использовать тот же API сокетов BSD, что и в Linux?

, 👍1

Обсуждение

просто позвольте потоку Arduino работать так, как это запланировано RTOS, @Juraj

@Juraj Я создаю задачи (используя vTaskCreate()) для передачи клиенту, как в подходе _accept then for k_ в Linux. Если я позволю основному потоку работать, не затормозит ли это выполнение других задач процессора?, @John Rennie

Добавьте небольшую задержку, если хотите. WiFiServer и WiFiClient реализованы через API сокетов Berkley/POSIX IDF/LwIP. Возможно, вы захотите использовать его напрямую., @Juraj

@Juraj Спасибо :-), @John Rennie


1 ответ


0

Похоже, нет способа сделать блок функции WiFiServer available() доступным до получения соединения. Если проблема связана с загрузкой процессора, решением, похоже, может быть небольшая задержка после вызова функции, как предложил Юрай в комментарии.

Если кому-то интересно, API сокетов работает отлично. Я составил код ниже для быстрого теста, и он работает как надо. Если подключиться к ESP32 через Telnet, выводится сообщение, а затем соединение закрывается:

#include <lwip/sockets.h>
#include "WiFi.h"

void ConnectWiFi() {
  WiFi.begin("my_ssid", "my_password", 6);
  int loopcnt = 0;
  while (WiFi.status() != WL_CONNECTED) {
    Serial.printf("Connecting: time %d, WiFi status = %d, signal = %d\n", loopcnt++, WiFi.status(), WiFi.RSSI());
    delay(1000);
  }
  Serial.printf("Connected: %s\n", WiFi.localIP().toString().c_str());
}

void setup() {
  Serial.begin(115200);
  ConnectWiFi();
}

void loop() {
  // Создать, привязать и прослушивать порт 23
  int sock_srv = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  
  struct sockaddr addr_in;
  memset(&addr_in, 0, sizeof(addr_in));
  struct sockaddr_in* p_addr_in = (struct sockaddr_in*) &addr_in;
  p_addr_in->sin_family = PF_INET;
  p_addr_in->sin_port = htons(23);
  p_addr_in->sin_addr.s_addr = INADDR_ANY;
  bind(sock_srv, &addr_in, sizeof(addr_in));

  listen(sock_srv, 1);
 
  // Цикл для обработки соединений
  while (true) {
    // Ожидание соединения
    sockaddr addr_client;
    memset(&addr_client, 0, sizeof(addr_client));
    int sock_client = accept(sock_srv, &addr_client, NULL);
    Serial.println("Accepted connection");

    // Просто завершаем сообщение и закрываем сокет
    String s = "Welcome and goodbye!\r\n";
    send(sock_client, s.c_str(), s.length(), 0);
    closesocket(sock_client);
  }   
}
,

Привет, добро пожаловать на Arduino:SE. Не уверен, было ли это ответом на ваш вопрос или дополнительной информацией (которую, вероятно, стоит добавить в ваш вопрос, а не публиковать как ответ)., @sempaiscuba

@sempaiscuba, верное замечание: это альтернативный подход, а не ответ на вопрос, можно ли заставить WiFiServer работать в режиме блокировки. Удалю, пока не получу ответ., @John Rennie