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.

Code: Untitled.c Select all

// Get all clients and send async message
static void wss_server_send_messages(httpd_handle_t* server)
{
bool send_messages = true;

// Send async message to all connected clients that use websocket protocol every 10 seconds
while (send_messages) {
vTaskDelay(10000 / portTICK_PERIOD_MS);

if (!*server) { // httpd might not have been created by now
continue;
}
size_t clients = max_clients;
int client_fds[max_clients];
if (httpd_get_client_list(*server, &clients, client_fds) == ESP_OK) {
for (size_t i=0; i < clients; ++i) {
int sock = client_fds[i];
if (httpd_ws_get_fd_info(*server, sock) == HTTPD_WS_CLIENT_WEBSOCKET) {
ESP_LOGI(TAG, "Active client (fd=%d) -> sending async message", sock);
struct async_resp_arg *resp_arg = malloc(sizeof(struct async_resp_arg));
resp_arg->hd = *server;
resp_arg->fd = sock;
if (httpd_queue_work(resp_arg->hd, send_hello, resp_arg) != ESP_OK) {
ESP_LOGE(TAG, "httpd_queue_work failed!");
send_messages = false;
break;
}
}
}
} else {
ESP_LOGE(TAG, "httpd_get_client_list failed!");
return;
}
}
}
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: Baidu [Spider] and 23 guests