ESP32 server AP na socketach przykładowy kod w Aruino
Kluczowe punkty
• tryb WIFI_AP
, SSID/hasło konfigurowalne
• statyczny adres IP 192.168.4.1/24
• serwer nasłuchuje na porcie 3333 (można zmienić)
• obsługa klientów przy użyciu select()
– brak blokowania głównej pętli
• przykład echo + prosta komenda LED
client
. socket()
, bind()
, listen()
, select()
. WebSocketsServer
). Niniejszy przykład wykorzystuje wariant 2 – najbliższy „czystym” socketom, ale pokazuję też, jak dodać WebSocket lub serwer HTTP, jeśli potrzebujesz front-endu w przeglądarce.
ESP32 udostępnia pełny stos lwIP. W trybie AP przydziela sobie adres 192.168.4.1 (domyślnie) oraz serwuje DHCP wszystkim klientom. Raw socket + select()
umożliwia obsługę wielu klientów bez wielowątkowości, co oszczędza RAM (≈8 kB/klient).
#include <WiFi.h>
#include <lwip/sockets.h> // niskopoziomowe sockety
#include <lwip/netdb.h>
constexpr char SSID[] = "ESP32_AP_Socket";
constexpr char PASS[] = "12345678"; // ≥8 znaków
constexpr uint16_t PORT = 3333; // port TCP
constexpr gpio_num_t LED = GPIO_NUM_2; // wbudowany LED
int srvSock = -1;
void setupAccessPoint()
{
WiFi.mode(WIFI_AP);
IPAddress ip(192,168,4,1), gw(192,168,4,1), mask(255,255,255,0);
WiFi.softAPConfig(ip, gw, mask);
if (!WiFi.softAP(SSID, PASS, 6, 0, 4)) { // kanał 6, widoczna, max 4 klientów
Serial.println(F("Błąd tworzenia AP!"));
while(true);
}
Serial.printf("AP uruchomione. IP: %s\n", WiFi.softAPIP().toString().c_str());
}
bool initSocketServer()
{
srvSock = socket(AF_INET, SOCK_STREAM, 0);
if (srvSock < 0) return false;
int opt = 1;
setsockopt(srvSock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(PORT);
if (bind(srvSock, (sockaddr*)&addr, sizeof(addr)) < 0) return false;
if (listen(srvSock, 4) < 0) return false;
Serial.printf("Socket server słucha na porcie %u\n", PORT);
return true;
}
void handleClients()
{
fd_set rfds;
timeval tv{0, 2000}; // 2 ms timeout
FD_ZERO(&rfds);
FD_SET(srvSock, &rfds);
int maxFd = srvSock;
// Dodaj już otwarte klienty do zestawu
for (int fd = 0; fd <= maxFd; ++fd)
if (fd != srvSock && fd != 0) FD_SET(fd, &rfds);
int act = select(maxFd + 1, &rfds, nullptr, nullptr, &tv);
if (act <= 0) return;
// Nowe połączenie
if (FD_ISSET(srvSock, &rfds)) {
int cli = accept(srvSock, nullptr, nullptr);
if (cli >= 0) {
Serial.printf("Nowy klient (%d)\n", cli);
fcntl(cli, F_SETFL, O_NONBLOCK); // nieblokujące
}
}
// Dane od istniejących klientów
char buf[256];
for (int fd = 3; fd <= maxFd; ++fd) {
if (fd == srvSock) continue;
if (!FD_ISSET(fd, &rfds)) continue;
int len = recv(fd, buf, sizeof(buf)-1, 0);
if (len <= 0) { // closed / error
close(fd);
Serial.printf("Klient %d zamknięty\n", fd);
continue;
}
buf[len] = 0;
Serial.printf("(%d) >> %s", fd, buf);
// Prosta logika: komenda LED\n
if (strncmp(buf, "LED ON", 6) == 0) digitalWrite(LED, HIGH);
if (strncmp(buf, "LED OFF",7) == 0) digitalWrite(LED, LOW);
// Echo
send(fd, buf, len, 0);
}
}
void setup()
{
Serial.begin(115200);
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
setupAccessPoint();
if (!initSocketServer()) {
Serial.println("Nie udało się uruchomić serwera socket!");
while(true);
}
}
void loop()
{
handleClients(); // ~2-3 ms
// zadania użytkownika ...
}
Test:
12345678
). telnet 192.168.4.1 3333
LED ON
lub LED OFF
, otrzymasz echo i zaświecisz diodę.WebSocketsServer
, nasłuch na porcie 81 i identyczna konfiguracja AP. Przydatne, gdy klientem jest przeglądarka.WebServer
w Arduino.• select()
zużywa mniej RAM-u niż tworzenie tasku dla każdego klienta.
• fcntl(fd, F_SETFL, O_NONBLOCK)
eliminuje zawieszanie się przy recv()
.
• Maks. 10–12 jednoczesnych socketów TCP przy 240 kB RAM (typowe dla ESP32-WROOM-32).
esp_task_wdt
) – sockety mogą się „zawiesić” przy ataku DoS. psramFound()
? użyj PSRAM > 4 kB na klienta). softAP()
max_connection
i listen(srvSock,N)
.select()
mógł sporadycznie zwracać -1 z errno 11; aktualizacja rozwiązuje problem. WiFi
musi być off), więc nie nadaje się do ultraniskiej energii.Przedstawiony szkic demonstruje, jak w kilkudziesięciu liniach uruchomić na ESP32:
• własną sieć Wi-Fi (AP)
• nieblokujący serwer TCP oparty na surowych socketach
• prostą logikę komend (LED) i echo danych
Dzięki użyciu select()
kod pozostaje responsywny, skalowalny i gotowy do rozbudowy o WebSockety lub REST API.