Websockets: Async send within an interrupt

tomfrance
Posts: 12
Joined: Wed Mar 17, 2021 3:50 pm

Websockets: Async send within an interrupt

Postby tomfrance » Mon Apr 05, 2021 4:39 pm

Hello team!

I am working on a project where the client should be informed about a data update via a push from the server. The server is an ESP32 running esp_http_server and the data push is triggered by e.g., an SPI triggered event running in a seperate task.

What's the best way to accomplish this? All websocket examples (e.g., https://github.com/espressif/esp-idf/bl ... o_server.c) assume that the relevant code to trigger an update is called from within the request handler that is associated with the websocket (in particular regarding the access to the *req pointer).

To be able do something like [1], [2], it seems like I need access to the socket fds, that are associated with a previous websocket request as well as the httpd_handle_t that was initialized when the server was started. While I can pass the latter to other freertos task, I have no idea how to obtain the FDs in a nice manner and especially how to track whether they are related to a WS socket.

[1] https://github.com/espressif/esp-idf/bl ... rver.c#L40
[2] https://github.com/espressif/esp-idf/bl ... rver.c#L56

I have found the API function httpd_get_client_list() - is this the best way to accomplish this with manual tracking in the WS request handler which of those is related to a WS?

Thank you,
Tom

tomfrance
Posts: 12
Joined: Wed Mar 17, 2021 3:50 pm

Re: Websockets: Async send within an interrupt

Postby tomfrance » Mon Apr 05, 2021 11:08 pm

I just found out that a lot of useful stuff (e.g. sock_db and its members ws_handshake_detect) can be retrieved from the struct

struct httpd_data

defined in esp_httpd_priv.h However it seems like this data is not meant to be accessed.

Any other way?

tomfrance
Posts: 12
Joined: Wed Mar 17, 2021 3:50 pm

Re: Websockets: Async send within an interrupt

Postby tomfrance » Thu Apr 08, 2021 7:17 am

Hi guys!

Any ideas on this matter?

Best,
Tom

dtaylor
Posts: 8
Joined: Tue Aug 24, 2021 5:27 pm

Re: Websockets: Async send within an interrupt

Postby dtaylor » Thu Aug 26, 2021 8:06 pm

I know this is old and likely solved for the OP, but thought I would offer help for anyone else working with websockets on the esp32.

I started down the same path with the example found at:
eps-idf/examples/protocols/http_server/ws_server

This was a good basic starting point.

A more complete example provided by espressif can be found at:
eps-idf/examples/protocols/https_server/wss_server


This example includes additional useful tools. For example registering a function for when a new client connects, when a client disconnects and provides for keep alive functionality.

Additionally it shows how to send to connected clients. Again, this example is much more complete than ws_server example. Here is the code where clients are accessed using only a handle to the server.
  1. // Get all clients and send async message
  2. static void wss_server_send_messages(httpd_handle_t* server)
  3. {
  4.     bool send_messages = true;
  5.  
  6.     // Send async message to all connected clients that use websocket protocol every 10 seconds
  7.     while (send_messages) {
  8.         vTaskDelay(10000 / portTICK_PERIOD_MS);
  9.  
  10.         if (!*server) { // httpd might not have been created by now
  11.             continue;
  12.         }
  13.         size_t clients = max_clients;
  14.         int    client_fds[max_clients];
  15.         if (httpd_get_client_list(*server, &clients, client_fds) == ESP_OK) {
  16.             for (size_t i=0; i < clients; ++i) {
  17.                 int sock = client_fds[i];
  18.                 if (httpd_ws_get_fd_info(*server, sock) == HTTPD_WS_CLIENT_WEBSOCKET) {
  19.                     ESP_LOGI(TAG, "Active client (fd=%d) -> sending async message", sock);
  20.                     struct async_resp_arg *resp_arg = malloc(sizeof(struct async_resp_arg));
  21.                     resp_arg->hd = *server;
  22.                     resp_arg->fd = sock;
  23.                     if (httpd_queue_work(resp_arg->hd, send_hello, resp_arg) != ESP_OK) {
  24.                         ESP_LOGE(TAG, "httpd_queue_work failed!");
  25.                         send_messages = false;
  26.                         break;
  27.                     }
  28.                 }
  29.             }
  30.         } else {
  31.             ESP_LOGE(TAG, "httpd_get_client_list failed!");
  32.             return;
  33.         }
  34.     }
  35. }
In this function, they do use the function httpd_get_client_list. A handle to the server is passed in and a pointer for size and client list. The size gets filled and the list as well which is the client_fds for each client.

Look at the rest of the example to see how the actual send happens after bing queued.

Who is online

Users browsing this forum: benrank, Bing [Bot], MicroController and 130 guests