Referência da Biblioteca ESP32 WebServer

Visão Geral

A biblioteca DIYables_ESP32_WebServer oferece uma solução completa para criar servidores web com várias páginas e suporte a WebSocket em placas ESP32.

Instalação

Passos Rápidos

Siga estas instruções passo a passo:

  • Se esta é a sua primeira vez usando o ESP32, consulte o tutorial sobre como configurar o ambiente do ESP32 no Arduino IDE.
  • Conecte a placa ESP32 ao seu computador com um cabo USB.
  • Abra o Arduino IDE no seu computador.
  • Selecione a placa ESP32 apropriada (por exemplo, ESP32) e a porta COM.
  • Abra o Library Manager clicando no ícone Library Manager no lado esquerdo do Arduino IDE.
  • Pesquise por Web Server for ESP32 e encontre a mWebSockets da DIYables.
  • Clique no botão Install para adicionar a biblioteca mWebSockets.
Biblioteca ESP32 Web Server

Suporte a WebSocket (Integrado)

A funcionalidade WebSocket agora está integrada diretamente nesta biblioteca!

A implementação do WebSocket é baseada na excelente biblioteca mWebSockets de Dawid Kurek, que foi integrada e otimizada especificamente para o ESP32 para facilitar o uso:

  • Não é necessário instalar nenhuma biblioteca adicional - o suporte a WebSocket já vem integrado
  • Otimizada para o ESP32 - Implementação simplificada específica para a plataforma
  • Compatível com WiFi - Usa a pilha WiFi nativa do ESP32
  • Compatível com a RFC 6455 - Suporte completo ao protocolo WebSocket
  • Comunicação em tempo real - Troca de dados bidirecional

Uso:

  • Para tudo (Web Server + WebSocket): Use #include <DIYables_ESP32_WebServer.h>
  • Só isso! - A funcionalidade WebSocket fica disponível automaticamente quando necessária
  • Eficiente em memória - O código WebSocket não utilizado é removido automaticamente pelo compilador

Créditos: Implementação do WebSocket adaptada da biblioteca mWebSockets (licença LGPL-2.1) de Dawid Kurek, modificada e integrada para uma compatibilidade perfeita com o ESP32.

Classes da Biblioteca

Classe DIYables_ESP32_WebServer

A classe principal para criar e gerenciar servidores web.

Construtor

DIYables_ESP32_WebServer(int port = 80)

Cria uma instância de servidor web na porta especificada (padrão: 80).

Métodos

begin()
void begin() void begin(const char* ssid, const char* password)

Inicia o servidor web e começa a escutar conexões de entrada.

Versões sobrecarregadas:

  • begin(): Inicia somente o servidor (o WiFi deve ser conectado separadamente pela sua aplicação)
  • begin(ssid, password): Conecta ao WiFi e inicia o servidor em uma única chamada (abordagem antiga)
setNotFoundHandler()
void setNotFoundHandler(RouteHandler handler)

Define um tratador personalizado para respostas 404 Not Found.

printWifiStatus()
void printWifiStatus()

Imprime o status da conexão WiFi e o endereço IP no Serial Monitor.

handleClient()
void handleClient()

Processa as requisições de clientes recebidas. Deve ser chamada repetidamente no loop principal.

on()
void on(const String &uri, HTTPMethod method, THandlerFunction fn) void on(const String &uri, THandlerFunction fn) // defaults to GET

Registra uma função tratadora para um URI e um método HTTP específicos.

Parâmetros:

  • uri: O caminho do URI (por exemplo, "/", "/led", "/api/data")
  • method: Método HTTP (GET, POST, PUT, DELETE, etc.)
  • fn: Função tratadora a ser executada quando a rota for acessada

Observação: Esta biblioteca usa o método addRoute() em vez de on(). Veja abaixo o uso correto.

addRoute()
void addRoute(const String &uri, RouteHandler handler)

Registra uma função tratadora para um URI específico. Este é o método realmente usado na biblioteca.

Formato da Função RouteHandler:

Os tratadores de rota devem seguir exatamente esta assinatura:

void handlerFunction(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData)

Parâmetros:

  • client: Referência a WiFiClient para enviar as respostas
  • method: Método HTTP como string ("GET", "POST", etc.)
  • request: URI completo da requisição
  • params: Parâmetros de consulta (objeto QueryParams)
  • jsonData: Conteúdo JSON para requisições POST (vazio para GET)

Exemplos de Implementação de Tratadores:

  1. Tratador GET Básico:
void handleHome(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) { if (method == "GET") { String response = "<html><body><h1>Hello World</h1></body></html>"; server.sendResponse(client, response.c_str()); } } void setup() { server.addRoute("/", handleHome); }
  1. Tratador de API JSON (GET e POST):
void handleApiData(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) { if (method == "POST") { if (jsonData.length() == 0) { client.println("HTTP/1.1 400 Bad Request"); client.println("Content-Type: application/json"); client.println("Connection: close"); client.println(); client.print("{\"status\":\"error\",\"message\":\"No JSON data received\"}"); return; } // Process JSON data StaticJsonDocument<200> doc; DeserializationError error = deserializeJson(doc, jsonData); if (error) { client.println("HTTP/1.1 400 Bad Request"); client.println("Content-Type: application/json"); client.println("Connection: close"); client.println(); client.print("{\"status\":\"error\",\"message\":\"Invalid JSON\"}"); return; } const char* key = doc["key"] | "none"; String response = "{\"status\":\"success\",\"received_key\":\"" + String(key) + "\"}"; server.sendResponse(client, response.c_str(), "application/json"); } else if (method == "GET") { String response = "{\"status\":\"success\",\"message\":\"GET request received\"}"; server.sendResponse(client, response.c_str(), "application/json"); } else { client.println("HTTP/1.1 405 Method Not Allowed"); client.println("Content-Type: application/json"); client.println("Connection: close"); client.println(); client.print("{\"status\":\"error\",\"message\":\"Method not allowed\"}"); } } void setup() { server.addRoute("/api/data", handleApiData); }
  1. Tratador de Parâmetros de Consulta:
void handleLedControl(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) { if (method == "GET") { // Access query parameters String action = params.getValue("action"); // ?action=on if (action == "on") { digitalWrite(LED_PIN, HIGH); server.sendResponse(client, "LED turned ON"); } else if (action == "off") { digitalWrite(LED_PIN, LOW); server.sendResponse(client, "LED turned OFF"); } else { client.println("HTTP/1.1 400 Bad Request"); client.println("Content-Type: text/plain"); client.println("Connection: close"); client.println(); client.print("Invalid action. Use ?action=on or ?action=off"); } } } void setup() { server.addRoute("/led", handleLedControl); }
sendResponse()
void sendResponse(WiFiClient& client, const char* content, const char* contentType = "text/html")

Envia uma resposta HTTP ao cliente.

Parâmetros:

  • client: Referência a WiFiClient (fornecida na função tratadora)
  • content: Conteúdo do corpo da resposta
  • contentType: Tipo MIME da resposta (padrão: "text/html")

Exemplos de Uso:

// Send HTML response server.sendResponse(client, "<h1>Hello World</h1>"); // Send JSON response server.sendResponse(client, "{\"status\":\"ok\"}", "application/json"); // Send plain text server.sendResponse(client, "Success", "text/plain");
Métodos de Autenticação
enableAuthentication()
void enableAuthentication(const char* username, const char* password, const char* realm = "ESP32 Server")

Habilita a Autenticação Básica HTTP para todas as rotas. Depois de habilitada, todas as rotas exigem autenticação.

Parâmetros:

  • username: Nome de usuário para autenticação (máx. 31 caracteres)
  • password: Senha para autenticação (máx. 31 caracteres)
  • realm: Realm de autenticação exibido no navegador (máx. 63 caracteres, opcional)

Exemplo de Uso:

// Enable authentication with default realm server.enableAuthentication("admin", "password123"); // Enable authentication with custom realm server.enableAuthentication("admin", "secure456", "My ESP32 Device");
disableAuthentication()
void disableAuthentication()

Desabilita a autenticação, tornando todas as rotas públicas novamente.

Exemplo de Uso:

server.disableAuthentication();
isAuthenticationEnabled()
bool isAuthenticationEnabled()

Retorna true se a autenticação estiver habilitada no momento, ou false caso contrário.

Exemplo de Uso:

if (server.isAuthenticationEnabled()) { Serial.println("Authentication is active"); } else { Serial.println("All routes are public"); }
send401()
void send401(WiFiClient& client)

Envia uma resposta 401 Unauthorized com o cabeçalho WWW-Authenticate correto. É chamada automaticamente quando a autenticação falha, mas pode ser usada manualmente em tratadores personalizados.

Exemplo de Uso:

// Manual 401 response in a custom handler server.send401(client);
Envio Manual de Respostas

Para ter mais controle sobre os cabeçalhos HTTP e os códigos de status:

void sendCustomResponse(WiFiClient& client) { client.println("HTTP/1.1 200 OK"); client.println("Content-Type: application/json"); client.println("Access-Control-Allow-Origin: *"); client.println("Connection: close"); client.println(); client.print("{\"custom\":\"response\"}"); }

Acesso aos Parâmetros de Consulta

Estrutura QueryParams

O objeto QueryParams contém os parâmetros de consulta analisados a partir da URL:

struct QueryParams { int count; // Number of parameters struct { const char* key; // Parameter name const char* value; // Parameter value } params[MAX_PARAMS]; }

Acessando os Parâmetros de Consulta

void handleWithParams(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) { // Access specific parameter by looping through String unit = "C"; // default value for (int i = 0; i < params.count; i++) { if (String(params.params[i].key) == "unit") { unit = params.params[i].value; break; } } // Use the parameter String response = "Unit selected: " + unit; server.sendResponse(client, response.c_str()); } // URL examples: // /temperature?unit=F // /led?state=on&brightness=50

Funções Auxiliares de Parâmetros

Crie funções auxiliares para facilitar o acesso aos parâmetros:

String getParam(const QueryParams& params, const String& key, const String& defaultValue = "") { for (int i = 0; i < params.count; i++) { if (String(params.params[i].key) == key) { return String(params.params[i].value); } } return defaultValue; } bool hasParam(const QueryParams& params, const String& key) { for (int i = 0; i < params.count; i++) { if (String(params.params[i].key) == key) { return true; } } return false; } // Usage in handlers: void handleLed(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) { String state = getParam(params, "state", "off"); int brightness = getParam(params, "brightness", "100").toInt(); if (state == "on") { digitalWrite(LED_PIN, HIGH); server.sendResponse(client, "LED turned ON with brightness " + String(brightness)); } else { digitalWrite(LED_PIN, LOW); server.sendResponse(client, "LED turned OFF"); } }

Classes WebSocket (Integradas)

WebSocketServer
WebSocketServer wsServer(81); // Port 81 for WebSocket

Alias de net::WebSocketServer - simplificado para uso por iniciantes.

WebSocket
WebSocket ws;

Alias de net::WebSocket - representa uma conexão WebSocket.

Métodos do WebSocket
begin()
void begin()

Inicia o servidor WebSocket.

loop()
void loop()

Processa os eventos do WebSocket. Chame-a no seu loop principal.

onConnection()
void onConnection([](WebSocket &ws) { // Handle new WebSocket connection });

Define o callback para novas conexões WebSocket.

onMessage()
void onMessage([](WebSocket &ws, const WebSocket::DataType dataType, const char *message, uint16_t length) { // Handle incoming WebSocket message });

Define o callback para mensagens WebSocket recebidas.

onClose()
void onClose([](WebSocket &ws, const WebSocket::CloseCode code, const char *reason, uint16_t length) { // Handle WebSocket connection close });

Define o callback para o encerramento de conexões WebSocket.

send()
void send(const String &message) void send(const char *message, size_t length)

Envia uma mensagem pelo WebSocket.

close()
void close()

Fecha a conexão WebSocket.

Métodos Adicionais do WebSocket
broadcastTXT()
void broadcastTXT(const char* payload) void broadcastTXT(const String& payload)

Transmite uma mensagem de texto para todos os clientes WebSocket conectados.

broadcastBIN()
void broadcastBIN(const uint8_t* payload, size_t length)

Transmite dados binários para todos os clientes WebSocket conectados.

connectedClients()
size_t connectedClients()

Retorna o número de clientes WebSocket conectados no momento.

isListening()
bool isListening()

Retorna true se o servidor WebSocket estiver escutando conexões ativamente.

Tipos de Evento do WebSocket
Enum DataType
  • WebSocket::DataType::TEXT - Tipo de mensagem de texto
  • WebSocket::DataType::BINARY - Tipo de dados binários
Enum CloseCode

Códigos padrão de encerramento do WebSocket, que indicam os motivos do término da conexão.

Uso Avançado do WebSocket

Configuração dos Tratadores de Eventos

void setup() { Serial.begin(9600); // Initialize WiFi and servers WiFi.begin(ssid, password); server.begin(); wsServer.begin(); // Set up WebSocket event handlers wsServer.onConnection([](WebSocket &ws) { Serial.print("Client connected from: "); Serial.println(ws.getRemoteIP()); ws.send("{\"type\":\"welcome\",\"message\":\"Connected to ESP32\"}"); }); wsServer.onMessage([](WebSocket &ws, const WebSocket::DataType dataType, const char *message, uint16_t length) { handleWebSocketMessage(ws, message, length); }); wsServer.onClose([](WebSocket &ws, const WebSocket::CloseCode code, const char *reason, uint16_t length) { Serial.println("Client disconnected"); }); }

Processamento de Mensagens

void handleWebSocketMessage(WebSocket &ws, const char *message, uint16_t length) { String msg = String(message); Serial.println("Received: " + msg); // JSON message handling if (msg.indexOf("\"type\":\"led\"") >= 0) { if (msg.indexOf("\"action\":\"on\"") >= 0) { digitalWrite(LED_PIN, HIGH); ws.send("{\"type\":\"led_status\",\"status\":\"on\"}"); } else if (msg.indexOf("\"action\":\"off\"") >= 0) { digitalWrite(LED_PIN, LOW); ws.send("{\"type\":\"led_status\",\"status\":\"off\"}"); } } // Echo functionality String response = "Echo: " + msg; ws.send(response.c_str()); }

Transmitindo Dados de Sensores

void loop() { server.handleClient(); wsServer.loop(); // Broadcast sensor data every 5 seconds static unsigned long lastBroadcast = 0; if (millis() - lastBroadcast > 5000) { if (wsServer.connectedClients() > 0) { float temperature = getTemperature(); String sensorData = "{"; sensorData += "\"type\":\"sensor\","; sensorData += "\"temperature\":" + String(temperature, 1) + ","; sensorData += "\"timestamp\":" + String(millis()); sensorData += "}"; wsServer.broadcastTXT(sensorData); } lastBroadcast = millis(); } }

Métodos HTTP

A biblioteca oferece suporte aos métodos HTTP padrão:

  • HTTP_GET
  • HTTP_POST
  • HTTP_PUT
  • HTTP_DELETE
  • HTTP_PATCH
  • HTTP_HEAD
  • HTTP_OPTIONS

Integração com JavaScript no Lado do Cliente

Conexão WebSocket Básica

// Connect to ESP32 WebSocket server const ws = new WebSocket('ws://your-esp32-ip:81'); ws.onopen = function(event) { console.log('Connected to ESP32 WebSocket'); document.getElementById('status').textContent = 'Connected'; }; ws.onmessage = function(event) { console.log('Received:', event.data); try { const data = JSON.parse(event.data); handleEsp32Message(data); } catch (e) { // Handle plain text messages console.log('Text message:', event.data); } }; ws.onclose = function(event) { console.log('Disconnected from ESP32'); document.getElementById('status').textContent = 'Disconnected'; // Auto-reconnect after 3 seconds setTimeout(connectWebSocket, 3000); }; ws.onerror = function(error) { console.error('WebSocket error:', error); };

Enviando Comandos

// Send LED control command function controlLED(action) { if (ws.readyState === WebSocket.OPEN) { const command = { type: 'led', action: action, timestamp: Date.now() }; ws.send(JSON.stringify(command)); } } // Send sensor request function requestSensorData() { if (ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({type: 'get_sensor'})); } }

Tratamento de Mensagens

function handleEsp32Message(data) { switch(data.type) { case 'sensor': updateTemperatureDisplay(data.temperature); break; case 'led_status': updateLEDStatus(data.status); break; case 'welcome': console.log('Welcome message:', data.message); break; default: console.log('Unknown message type:', data); } }

Exemplos de WebSocket

Servidor Echo Simples

wsServer.onMessage([](WebSocket &ws, const WebSocket::DataType dataType, const char *message, uint16_t length) { String response = "Echo: " + String(message); ws.send(response.c_str()); });

Processamento de Comandos JSON

void processWebSocketCommand(WebSocket &ws, const String& message) { if (message.indexOf("\"type\":\"led\"") >= 0) { if (message.indexOf("\"action\":\"on\"") >= 0) { digitalWrite(LED_PIN, HIGH); ws.send("{\"type\":\"led_status\",\"status\":\"on\",\"success\":true}"); } else if (message.indexOf("\"action\":\"off\"") >= 0) { digitalWrite(LED_PIN, LOW); ws.send("{\"type\":\"led_status\",\"status\":\"off\",\"success\":true}"); } } else if (message.indexOf("\"type\":\"get_sensor\"") >= 0) { float temp = getTemperature(); String response = "{\"type\":\"sensor\",\"temperature\":" + String(temp, 1) + "}"; ws.send(response.c_str()); } }

Implementação de Heartbeat

void setupHeartbeat() { static unsigned long lastHeartbeat = 0; if (millis() - lastHeartbeat > 30000) { // Every 30 seconds if (wsServer.connectedClients() > 0) { String heartbeat = "{\"type\":\"heartbeat\",\"timestamp\":" + String(millis()) + "}"; wsServer.broadcastTXT(heartbeat); } lastHeartbeat = millis(); } }

Solução de Problemas do WebSocket

Problemas Comuns

Falha na Conexão WebSocket

  • Verifique se a porta do servidor WebSocket (padrão: 81) está acessível
  • Confirme que o endereço IP do ESP32 está correto e acessível
  • Use as ferramentas de desenvolvedor do navegador para verificar erros na conexão WebSocket

Mensagens Não Estão Sendo Recebidas

  • Verifique no Serial Monitor os logs de eventos do WebSocket
  • Confirme que o formato da mensagem JSON está correto
  • Teste com mensagens de texto simples antes de usar JSON
  • Confirme que o tamanho da mensagem não excede os limites do buffer

Alto Uso de Memória

  • Limite o número de conexões WebSocket simultâneas
  • Limpe os buffers de mensagens regularmente
  • Use um tratamento eficiente de String (evite concatenações frequentes)
  • Monitore a memória heap livre

Auxiliares de Depuração

void debugWebSocket() { Serial.println("=== WebSocket Debug Info ==="); Serial.println("Connected clients: " + String(wsServer.connectedClients())); Serial.println("Server listening: " + String(wsServer.isListening() ? "Yes" : "No")); Serial.println("Free memory: " + String(ESP.getFreeHeap()) + " bytes"); Serial.println("Uptime: " + String(millis() / 1000) + " seconds"); Serial.println("============================"); }

Monitoramento de Desempenho

void monitorPerformance() { static unsigned long lastCheck = 0; static int messageCount = 0; messageCount++; if (millis() - lastCheck > 10000) { // Every 10 seconds Serial.println("Messages/10s: " + String(messageCount)); Serial.println("Clients: " + String(wsServer.connectedClients())); messageCount = 0; lastCheck = millis(); } }

A biblioteca oferece suporte a templates HTML com substituição de marcadores:

String response = HTML_TEMPLATE; response.replace("%TEMPERATURE%", String(temperature)); response.replace("%LED_STATUS%", ledStatus ? "ON" : "OFF"); server.send(200, "text/html", response);

Marcadores comuns:

  • %TEMPERATURE% - Valor da temperatura
  • %LED_STATUS% - Status do LED
  • %QUERY_PARAM% - Valores dos parâmetros de consulta

Recursos Avançados do Servidor Web

Suporte a CORS

Habilite requisições entre origens (cross-origin) para aplicações web:

// Handle preflight OPTIONS requests server.on("/api/data", HTTP_OPTIONS, []() { server.sendHeader("Access-Control-Allow-Origin", "*"); server.sendHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); server.sendHeader("Access-Control-Allow-Headers", "Content-Type"); server.send(200); }); // Add CORS headers to all responses server.sendHeader("Access-Control-Allow-Origin", "*"); server.sendHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE"); server.sendHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");

Auxiliares de Resposta JSON

Simplifique o desenvolvimento de APIs JSON:

void sendJsonResponse(int statusCode, const String& json) { server.send(statusCode, "application/json", json); } void sendError(int statusCode, const String& message) { String error = "{\"error\":\"" + message + "\"}"; sendJsonResponse(statusCode, error); } // Usage sendJsonResponse(200, "{\"status\":\"success\",\"data\":\"value\"}"); sendError(400, "Invalid request format");

Validação de Requisições

Implemente uma validação de entrada robusta:

bool isValidJsonAction(const String& action) { return (action == "on" || action == "off" || action == "toggle"); } bool validateRequiredFields(const String& jsonData, const String& field) { return (jsonData.indexOf("\"" + field + "\":") >= 0); } server.on("/api/control", HTTP_POST, []() { if (!server.hasArg("plain")) { sendError(400, "JSON body required"); return; } String body = server.arg("plain"); if (!validateRequiredFields(body, "action")) { sendError(400, "Missing required field: action"); return; } // Process valid request... });

Processamento JSON Avançado

Para um tratamento complexo de JSON com a biblioteca ArduinoJson:

#include <ArduinoJson.h> void handleJsonRequest() { String requestBody = server.arg("plain"); StaticJsonDocument<200> doc; DeserializationError error = deserializeJson(doc, requestBody); if (error) { sendError(400, "Invalid JSON format"); return; } // Extract values safely const char* action = doc["action"] | "none"; int value = doc["value"] | 0; bool enabled = doc["enabled"] | false; // Create response StaticJsonDocument<200> response; response["status"] = "success"; response["received_action"] = action; response["received_value"] = value; String responseString; serializeJson(response, responseString); sendJsonResponse(200, responseString); }

Tratamento de Erros

Tratador 404 Padrão

A biblioteca oferece uma página de erro 404 padrão. Você pode substituí-la:

server.onNotFound([]() { server.send(404, "text/html", "<h1>Custom 404 Page</h1>"); });

Boas Práticas

  1. Gerenciamento de Memória: Use a macro F() para literais de string armazenados na memória flash
  2. Código Não Bloqueante: Mantenha as funções tratadoras leves para não bloquear o servidor
  3. Segurança: Valide os parâmetros de entrada e trate a saída
  4. Desempenho: Use códigos de status HTTP e tipos de conteúdo adequados
  5. WebSocket: Trate corretamente os estados de conexão e implemente a lógica de reconexão

Depuração

Habilite a depuração serial para monitorar a atividade do servidor:

void setup() { Serial.begin(9600); // ... rest of setup } void loop() { server.handleClient(); if (Serial.available()) { String command = Serial.readString(); Serial.println("Debug: " + command); } }

Compatibilidade

  • ESP32: Totalmente suportado
  • Biblioteca WiFi: Necessária (incluída no Arduino IDE)
  • Requisitos de Memória: Mínimo de 32KB de flash, 2KB de RAM

Limitações

Limitações do Servidor Web

  • Máximo de conexões HTTP simultâneas: 4 (limitação de hardware)
  • Comprimento máximo da URL: 256 caracteres
  • Marcadores de template: Sem substituições aninhadas

Limitações do WebSocket

  • Tamanho máximo da mensagem WebSocket: 1KB por mensagem
  • Máximo de conexões WebSocket simultâneas: 4-6 (dependendo da memória disponível)
  • Mensagens fragmentadas: Tratadas automaticamente, mas podem afetar o desempenho
  • Tamanho das mensagens binárias: Limitado pela RAM disponível
  • Tempo limite de conexão: 60 segundos por padrão (configurável)

Restrições de Memória

  • Memória flash mínima necessária: 32KB
  • RAM mínima necessária: 2KB para a funcionalidade básica
  • Sobrecarga do WebSocket: ~200-500 bytes por conexão
  • Buffer de mensagens: ~1KB por conexão ativa

※ NOSSAS MENSAGENS

  • Fique à vontade para compartilhar o link deste tutorial. Porém, por favor, não use nosso conteúdo em outros sites. Investimos muito esforço e tempo para criar este conteúdo, por favor respeite nosso trabalho!