ArduinoWebsockets icon indicating copy to clipboard operation
ArduinoWebsockets copied to clipboard

Multiple polls for 1 websocket client when using firefox as client

Open chubby1968 opened this issue 6 years ago • 2 comments

Describe the bug ESP32 is configured as server that accepts multiple clients. When connecting from firefox browser using server.poll(), two clients are registered (in most cases).

When this happens, no more code is executed. (It appears to be trapped in handshake part of server.accept() ).

To Reproduce Using below code, connect to the esp32 board from firefox browser.

  • Library version 0.4.14
  • Board: ESP32-CAM
  • Firefox 71.0 (64-bit)

Expected behavior Only 1 client is added to the list for each new connection (which is what happens in chrome).

Code

#include <WiFi.h>
#include <ArduinoWebsockets.h>
using namespace websockets;

const char *ssid = "xxxx";
const char *password = "xxxx";
const int maxClients = 4; // Accept up to 4 connections

WebsocketsServer server;
WebsocketsClient clients[maxClients];
int nClients = 0;

void setup()
{
  Serial.begin(115200);
  while (!Serial)
    ;

  // WIFI SETUP
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("WiFi connected, IP: ");
  Serial.println(WiFi.localIP());

  // WEBSOCKET: Open websocket on port 80
  server.listen(80);
  Serial.print("Is server live? ");
  Serial.println(server.available());
}

void loop()
{
  if (server.available())
  {
    // if there is a client that wants to connect
    if (server.poll() && nClients < maxClients)
    {
      //accept the connection and register callback
      Serial.print("Accepting a new client! Number of clients accepted: ");
      Serial.println(nClients + 1);
      WebsocketsClient client = server.accept();
      client.onMessage(onMessage);

      // store it for later use
      clients[nClients] = client;
      nClients++;
      delay(10);
    }

    // check for updates in all clients
    pollAllClients();

    delay(10);
  }
}

// this method goes thrugh every client and polls for new messages and events
void pollAllClients()
{
  for (int i = 0; i < nClients; i++)
  {
    clients[i].poll();
  }
}

// this callback is common for all clients, the client that sent that
// message is the one that gets the echo response
void onMessage(WebsocketsClient &client, WebsocketsMessage message)
{
  Serial.print("Got Message: ");
  Serial.print(message.data());
  Serial.println(", Sending Echo.");
  client.send("Echo: " + message.data());
}
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <link rel="stylesheet" href="../css/style.css" />
        <script src="../js/websocket.js" defer></script>
        <title>Websocket demo</title>
    </head>
    <body>
        <table>
            <thead>
                <th>Status</th>
                <th>Messages received</th>
            </thead>
            <tbody>
                <td id="status">Not connected</td>
                <td id="messages"></td>
            </tbody>
        </table>
        <form>
            <input type="button" id="msg_button" value="Send a msg" />
            <input type="text" placeholder="IP of server" name="IP" id="IP" value="" />
            <input type="button" id="IP_button" value="Configure IP" />
        </form>
    </body>
</html>
let messages = document.querySelector("#messages");
let status = document.querySelector("#status");
let ws;

document.querySelector("#IP_button").onclick = () => {
    
    if(typeof ws !== 'undefined'){
        ws.close();
    }
    ws = new WebSocket("ws://" + document.querySelector("#IP").value);
    status.innerHTML = "Websocket " + ws.readyState;

    ws.onopen = () => {
        status.innerHTML = "Websocket open";
        let i = 0;

        document.querySelector("#msg_button").onclick = () => {
            console.log("click");
            ws.send(i++);
        };

        ws.onmessage = event => {
            console.log(event);
            let txt = messages.innerHTML;
            messages.innerHTML = txt + "<br>" + event.data;
        };
    };

    ws.onclose = () => {
        status.innerHTML = "Websocket closed";
    };

    ws.onerror = event => {
        console.log(event);
        status.innerHTML = "Cannot connect to " + event.target.url;
    };
};

chubby1968 avatar Dec 11 '19 15:12 chubby1968

Hi,

So, I was able to reproduce. The problem as far as I understand it has nothing to do with the library itself, it seems like esp32's WiFiServer impl claims that there is a client when there is not. I will keep looking into it, meanwhile, you can check if the client that you got is connected by calling client.available. If it returns false, just skip that client.

Gil.

gilmaimon avatar Dec 17 '19 19:12 gilmaimon

Was there any solution to this? I am working with this otherwise great implementation, but looping even for 1 client does not seem to work. Always gets disconnected after the initial message was properly received (without me calling cloe() on the server)...

Cnets-io avatar Mar 18 '22 16:03 Cnets-io