完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
单片机学习笔记 - 08 - WebSocket客户端
一、应用层协议 科普概念 在看例程之前先补补概念,我现在还是一脸懵逼,不知道这个是什么的状态。明明上一层的tcp已经能够通讯了,怎么又加多了一层。
二、编程指南 翻译 1. 概述
2. 特点
3. 配置 1)URI
// 最小的配置: const esp_websocket_client_config_t ws_cfg = { .uri = "ws://echo.websocket.org", }; // WebSocket客户端支持在URI中同时使用路径和查询。示例: const esp_websocket_client_config_t ws_cfg = { .uri = "ws://echo.websocket.org/connectionhandler?id=104", }; // 如果在 esp_websocket_client_config_t 中有任何与URI相关的选项,则URI定义的选项将被覆盖。示例: const esp_websocket_client_config_t ws_cfg = { .uri = "ws://echo.websocket.org:123", .port = 4567, //WebSocket客户端将使用端口4567连接到websocket.org }; 2)TLS
// 配置 const esp_websocket_client_config_t ws_cfg = { .uri = "wss://echo.websocket.org", .cert_pem = (const char *)websocket_org_pem_start, }; 3)子协议
// 配置结构中的子协议字段可用于请求子协议 const esp_websocket_client_config_t ws_cfg = { .uri = "ws://websocket.org", .subprotocol = "soap", }; 4. 事件
// 如果客户端句柄需要在事件处理程序中,它可以通过传递给事件处理程序的指针访问: esp_websocket_client_handle_t client = (esp_websocket_client_handle_t)handler_args; 5. 限制和已知问题
6. 应用举例
// WebSocket客户端支持以文本数据帧的形式发送数据,这告知应用层有效载荷数据是编码为UTF-8的文本数据。例子: esp_websocket_client_send_text(client, data, len, portMAX_DELAY); 三、例程解析
ESP_LOGI(TAG, "[APP] Startup.."); ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version()); esp_log_level_set("*", ESP_LOG_INFO); esp_log_level_set("WEBSOCKET_CLIENT", ESP_LOG_DEBUG); esp_log_level_set("TRANS_TCP", ESP_LOG_DEBUG); ESP_ERROR_CHECK(nvs_flash_init()); ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. * Read "Establishing Wi-Fi or Ethernet Connection" section in * examples/protocols/README.md for more information about this function. */ ESP_ERROR_CHECK(example_connect());
// 定时器超时函数 static void shutdown_signaler(TimerHandle_t xTimer) { ESP_LOGI(TAG, "No data received for %d seconds, signaling shutdown", NO_DATA_TIMEOUT_SEC); // 宏定义 释放信号量 xSemaphoreGive(shutdown_sema); } // 创建一个新的软件计时器实例,并返回一个句柄,通过这个句柄可以引用创建的软件计时器。 shutdown_signal_timer = xTimerCreate("Websocket shutdown timer", // 只是一个文本名称,不被内核使用。 NO_DATA_TIMEOUT_SEC * 1000 / portTICK_PERIOD_MS, // 计时器周期(单位是tick)。 pdFALSE, // 计时器将在到期时自动重新加载。(不会) NULL, // 为每个计时器分配一个唯一的id等于它的数组索引。 shutdown_signaler); // 每个计时器在到期时调用同一个回调。 // 创建一个新的二进制信号量实例,并返回一个句柄,通过这个句柄可以引用新的信号量。 shutdown_sema = xSemaphoreCreateBinary();
// 打包函数,用于获取uri字符串 #if CONFIG_WEBSOCKET_URI_FROM_STDIN static void get_string(char *line, size_t size) { int count = 0; while (count < size) { int c = fgetc(stdin); if (c == 'n') { line[count] = ' '; break; } else if (c > 0 && c < 127) { line[count] = c; ++count; } vTaskDelay(10 / portTICK_PERIOD_MS); } } #endif /* CONFIG_WEBSOCKET_URI_FROM_STDIN */ // 是否需要手动输入uri地址,若配置中不存在则需要 #if CONFIG_WEBSOCKET_URI_FROM_STDIN char line[128]; ESP_LOGI(TAG, "Please enter uri of websocket endpoint"); get_string(line, sizeof(line)); websocket_cfg.uri = line; ESP_LOGI(TAG, "Endpoint uri: %sn", line); #else // 直接获取uri地址 websocket_cfg.uri = CONFIG_WEBSOCKET_URI; #endif /* CONFIG_WEBSOCKET_URI_FROM_STDIN */ /* 这个函数必须是第一个调用的函数,它返回一个 esp_websocket_client_handle_t , 你必须把它作为接口中其他函数的输入。 当操作完成时,这个调用必须有一个对应的 esp_websocket_client_destroy 调用。 */ esp_websocket_client_handle_t client = esp_websocket_client_init(&websocket_cfg); // 注册Websocket事件。 esp_websocket_register_events(client, WEBSOCKET_EVENT_ANY, websocket_event_handler, (void *)client); // 打开WebSocket连接。 esp_websocket_client_start(client);
static void websocket_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) { esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data; switch (event_id) { // 客户端与服务器成功建立连接。客户机现在可以发送和接收数据了。不包含事件数据。 case WEBSOCKET_EVENT_CONNECTED: ESP_LOGI(TAG, "WEBSOCKET_EVENT_CONNECTED"); break; // 由于传输层读取数据失败(例如服务器不可用),客户端已经终止连接。不包含事件数据。 case WEBSOCKET_EVENT_DISCONNECTED: ESP_LOGI(TAG, "WEBSOCKET_EVENT_DISCONNECTED"); break; // 客户端已经成功接收并解析了一个`WebSocket`帧。 // 事件数据包含一个指向有效载荷数据的指针,有效载荷数据的长度以及接收帧的操作码。 // 如果长度超过缓冲区大小,则消息可能被分割成多个事件。 // 此事件也将被发布为非有效载荷帧,例如pong或连接关闭帧。 case WEBSOCKET_EVENT_DATA: ESP_LOGI(TAG, "WEBSOCKET_EVENT_DATA"); ESP_LOGI(TAG, "Received opcode=%d", data->op_code); ESP_LOGW(TAG, "Received=%.*s", data->data_len, (char *)data->data_ptr); ESP_LOGW(TAG, "Total payload length=%d, data_len=%d, current payload offset=%drn", data->payload_len, data->data_len, data->payload_offset); xTimerReset(shutdown_signal_timer, portMAX_DELAY); break; // 在客户端的当前实现中未使用。 case WEBSOCKET_EVENT_ERROR: ESP_LOGI(TAG, "WEBSOCKET_EVENT_ERROR"); break; } }
// 启动定时器 xTimerStart(shutdown_signal_timer, portMAX_DELAY); char data[32]; int i = 0; while (i < 10) { // 检查WebSocket客户端连接状态。 if (esp_websocket_client_is_connected(client)) { int len = sprintf(data, "hello %04d", i++); ESP_LOGI(TAG, "Sending %s", data); // 将文本数据写入WebSocket连接 esp_websocket_client_send_text(client, data, len, portMAX_DELAY); } vTaskDelay(1000 / portTICK_RATE_MS); }
// 宏获取信号量 xSemaphoreTake(shutdown_sema, portMAX_DELAY); /* 停止WebSocket连接而没有WebSocket关闭握手。 此API停止ws客户端并直接关闭TCP连接,而不发送关闭帧。 使用 esp_websocket_client_close() 以一种干净的方式关闭连接是一个很好的实践。 */ esp_websocket_client_stop(client); ESP_LOGI(TAG, "Websocket Stopped"); /* 销毁 WebSocket 连接并释放所有资源。 这个函数必须是会话调用的最后一个函数。 它与 esp_websocket_client_init 函数相反, 调用时必须使用与 esp_websocket_client_init 调用返回的输入相同的句柄。 这可能会关闭该句柄使用过的所有连接。 */ esp_websocket_client_destroy(client); 四、试验总结 1. 查看握手协议
2. 连接 Websocket服务器
【小插曲】使用 node.js 编写简易 Websocket服务器
3. 实验现象
4. 总结的总结
|
|
|
|
只有小组成员才能发言,加入小组>>
imx6ull 和 lan8742 工作起来不正常, ping 老是丢包
3544 浏览 0 评论
3455 浏览 9 评论
3131 浏览 16 评论
3642 浏览 1 评论
9354 浏览 16 评论
1501浏览 3评论
732浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
751浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2539浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
2068浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-5-6 22:29 , Processed in 1.207987 second(s), Total 76, Slave 57 queries .
Powered by 电子发烧友网
© 2015 www.ringvoyeur.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191