ESP32 TCP_Client调试

本文介绍如何使用VSCODE和ESP-IDF搭建ESP32的TCP客户端,并通过示例代码展示TCP通信的过程,包括连接建立、数据发送及速度测量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

前言

一、新建工程

二、修改代码

三、测试


前言

使用VSCODE+ESP-IDF 实现ESP32的TCP客户端和TCP服务端通信

一、新建工程

配置ESP32连接的网络 

二、修改代码

修改tcp_client.c的代码如下

/* BSD Socket API Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "protocol_examples_common.h"
#include "addr_from_stdin.h"
#include "lwip/err.h"
#include "lwip/sockets.h"

/*注意修改这里TCP连接的IP地址和端口号*/
#if defined(CONFIG_EXAMPLE_IPV4)
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV4_ADDR
#elif defined(CONFIG_EXAMPLE_IPV6)
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV6_ADDR
#else
#define HOST_IP_ADDR ""
#endif

#define PORT CONFIG_EXAMPLE_PORT

static const char *TAG = "example";
static const char *payload = "hello world\r\n";


typedef struct 
{       
    unsigned char TCP_ClientTag[1024 * 100];     
    // unsigned char TCP_DataBuffer[50];
    char *pData;
} _TCP_Data ;
_TCP_Data TCP_Data;
void tcp_client_task(void *pvParameters)
{
    char rx_buffer[128];
    char host_ip[] = HOST_IP_ADDR;
    int addr_family = 0;
    int ip_protocol = 0;

    while (1) {

        struct sockaddr_in dest_addr;
        dest_addr.sin_addr.s_addr = inet_addr(host_ip);
        dest_addr.sin_family = AF_INET;
        dest_addr.sin_port = htons(PORT);
        addr_family = AF_INET;
        ip_protocol = IPPROTO_IP;

        int sock =  socket(addr_family, SOCK_STREAM, ip_protocol);
        if (sock < 0) {
            ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
            break;
        }
        ESP_LOGI(TAG, "Socket created, connecting to %s:%d", host_ip, PORT);

        int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
        if (err != 0) {
            ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno);
            break;
        }
        ESP_LOGI(TAG, "Successfully connected");
        // int err = 0;
        static unsigned int SendDataCnt = 0;
        static unsigned int Time1 = 0;
        static unsigned int Time2 = 0;
        while (1) {
            
            unsigned int LocalUserID = 1;
            unsigned int FarUserID   = 2;
            unsigned int DataLen     = 1024 * 40;
            
            TCP_Data.TCP_ClientTag[0] = 0xA1;
            TCP_Data.TCP_ClientTag[1] = 0xA2;

            TCP_Data.TCP_ClientTag[2] = LocalUserID;
            TCP_Data.TCP_ClientTag[3] = LocalUserID>>8;
            TCP_Data.TCP_ClientTag[4] = LocalUserID>>16;
            TCP_Data.TCP_ClientTag[5] = LocalUserID>>24;

            TCP_Data.TCP_ClientTag[6] = FarUserID;
            TCP_Data.TCP_ClientTag[7] = FarUserID>>8;
            TCP_Data.TCP_ClientTag[8] = FarUserID>>16;
            TCP_Data.TCP_ClientTag[9] = FarUserID>>24;

            TCP_Data.TCP_ClientTag[10] = DataLen;
            TCP_Data.TCP_ClientTag[11] = DataLen>>8;
            TCP_Data.TCP_ClientTag[12] = DataLen>>16;
            TCP_Data.TCP_ClientTag[13] = DataLen>>24;

            TCP_Data.TCP_ClientTag[14] = 0xA3;
            TCP_Data.TCP_ClientTag[15] = 0xA4;
            // strcpy(&TCP_Data.TCP_DataBuffer,payload);
            err = send(sock,&TCP_Data,1024 * 100, 0);
            //send(sock,payload,strlen(payload), 0);
            if (err < 0) {
                ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
                break;
            }
            Time2 = esp_log_timestamp();
            SendDataCnt+=err;
            if((Time2 - Time1) > 1000)
            {
                float TCP_Speed = ((float)SendDataCnt)/((float)(Time2 - Time1)/1000.0f); /*bytes/s*/
                ESP_LOGI(TAG,"TCP speed = %f kb/s\r\n",TCP_Speed / 1024.0f);

                Time1 = Time2;
                SendDataCnt = 0;
            }
            // int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
            // // Error occurred during receiving
            // if (len < 0) {
            //     ESP_LOGE(TAG, "recv failed: errno %d", errno);
            //     break;
            // }
            // // Data received
            // else {
            //     rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string
            //     ESP_LOGI(TAG, "Received %d bytes from %s:", len, host_ip);
            //     ESP_LOGI(TAG, "%s", rx_buffer);
            // }

            vTaskDelay(1);//1 / portTICK_PERIOD_MS
        }

        if (sock != -1) {
            ESP_LOGE(TAG, "Shutting down socket and restarting...");
            shutdown(sock, 0);
            close(sock);
        }
    }
    vTaskDelete(NULL);
}

void app_main(void)
{
    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());

    xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, NULL);
}

编译下载后

 

三、测试

随便下载一个TCP/UDP网络助手TCP/UDP网络助手

 

需要注意的是,买的模块质量参差不齐,距离远的时候可能会连接不到WIFI,或者通信的速度非常的慢!巨坑!!!

<think>好的,我需要帮助用户修改他们的MQTT连接代码以连接到华为云。用户提供的代码是使用ESP-MQTT库的,当前配置可能存在问题。首先,我需要回顾华为云的MQTT连接要求,确保代码中的参数都符合这些要求。 首先,用户代码中的`esp_mqtt_client_config_t`结构体配置了broker的URI、客户端ID、用户名、密码、CA证书、事件处理函数和保活时间。根据华为云的文档,通常需要正确的CA证书,以及正确的客户端认证信息。用户提到需要替换华为云CA证书,所以需要确认`huawei_root_ca_pem`是否正确,或者是否需要从华为云下载最新的根证书并嵌入代码中。 然后,检查生成客户端ID、用户名和密码的函数`generate_mqtt_info`是否正确。华为云可能使用特定的生成规则,比如客户端ID可能是设备ID,用户名可能包含设备ID和产品ID,密码可能是使用密钥生成的Token,可能需要使用HMAC-SHA256算法。如果用户当前的生成方法不符合,这会导致连接失败。 接下来,查看华为云是否需要TLS/SSL加密。代码中已经指定了`cert_pem`,说明启用了SSL,但需要确认端口是否正确,比如8883端口用于SSL连接,而1883是普通端口。检查`CONFIG_SERVER`是否配置为正确的MQTT SSL端点,例如"mqtts://your-endpoint:8883"。 另外,注意`esp_mqtt_client_config_t`结构体的成员是否正确赋值。例如,某些版本的ESP-IDF中,结构体成员可能有变化,比如`broker.address.uri`是否正确,或者是否需要使用`host`和`port`分开配置。需要查阅当前使用的ESP-IDF版本的文档,确保配置结构正确。 用户提供的引用中提到了在`mqtt_event_handler`函数中添加订阅代码,特别是在MQTT_CONNECTED事件后订阅主题。当前代码中是否在连接成功后订阅了所需的主题?如果没有,需要添加订阅代码,否则无法接收消息。例如,在事件处理函数中,当事件为`MQTT_EVENT_CONNECTED`时,调用`esp_mqtt_client_subscribe`来订阅主题。 此外,华为云可能要求使用特定的协议版本,比如MQTT 3.1.1,需要确认ESP-MQTT客户端是否默认使用该版本,或者是否需要显式设置。 总结可能的修改点: 1. 确认CA证书是否正确,并替换为华为云提供的PEM格式证书。 2. 检查客户端ID、用户名和密码的生成逻辑是否符合华为云的要求。 3. 确保MQTT的URI正确,使用mqtts://协议和正确的端口。 4. 在连接成功后订阅必要的主题。 5. 验证ESP-IDF版本中结构体配置的正确性,可能需要调整成员名称。 6. 处理可能的SSL/TLS配置,如证书验证方式。 现在根据这些思考,逐步指导用户修改代码,并引用提供的参考资料,特别是关于事件处理中添加订阅的部分,以及MQTT客户端的配置。</think>### 修改华为云MQTT连接代码的步骤说明 1. **更新CA证书配置** - 从华为云官网下载最新的根证书(如`DigiCertGlobalRootCA.pem`),将其转换为字符串格式嵌入代码 - 替换原有`huawei_root_ca_pem`变量定义: ```c static const char huawei_root_ca_pem[] = "-----BEGIN CERTIFICATE-----\n" "MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n" "...完整证书内容...\n" "-----END CERTIFICATE-----\n"; ``` 2. **验证认证信息生成逻辑** - 华为云设备密码通常使用HMAC-SHA256加密算法生成,示例函数: ```c void generate_mqtt_info(char *client_id, char *username, char *password) { // 设备ID和产品ID从配置读取 const char *device_id = CONFIG_DEVICE_ID; const char *product_id = CONFIG_PRODUCT_ID; // 客户端ID格式:设备ID snprintf(client_id, 128, "%s", device_id); // 用户名格式:产品ID+设备ID snprintf(username, 128, "%s_%s", product_id, device_id); // 密码生成(使用设备密钥+时间戳) const char *secret = CONFIG_DEVICE_SECRET; char timestamp[20]; get_timestamp_str(timestamp); // 获取当前时间戳字符串 hmac_sha256(secret, timestamp, password); // 实现HMAC-SHA256算法 } ``` 3. **配置MQTT连接参数** - 修改`esp_mqtt_client_config_t`结构体,补充必要参数: ```c esp_mqtt_client_config_t mqtt_cfg = { .broker = { .address.uri = "mqtts://your-endpoint:8883", // 替换为实际地址 }, .credentials = { .client_id = client_id, .username = username, .authentication = { .password = password, .certificate = huawei_root_ca_pem // 证书赋值到正确字段 } }, .keepalive = 120, .task_prio = 5, .event_handle = mqtt_event_handler }; ``` - 注意:不同ESP-IDF版本中字段名可能变化(如`.cert_pem`可能需改为`.authentication.certificate`) 4. **添加连接后订阅逻辑** 在`mqtt_event_handler`函数中处理连接成功事件: ```c static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) { esp_mqtt_event_handle_t event = event_data; switch ((esp_mqtt_event_id_t)event_id) { case MQTT_EVENT_CONNECTED: // 连接成功后订阅主题 esp_mqtt_client_subscribe(client, "/a1Pvdruq4mz/FTY_Temp_01/user/get", 1); break; case MQTT_EVENT_DATA: // 处理收到的消息 printf("Received: %.*s\n", event->data_len, event->data); break; // 其他事件处理... } } ``` 5. **关键配置检查项** | 配置项 | 要求示例 | 检查方法 | |-----------------------|-----------------------------|---------------------------| | 连接协议 | mqtts:// (SSL加密) | URI以`mqtts://`开头 | | 端口号 | 8883 | 华为云文档确认 | | ClientID | 设备唯一标识 | 与设备控制台信息一致 | | 用户名/密码生成规则 | 产品ID+设备ID+HMAC-SHA256 | 使用华为云工具验证 | ### 验证步骤 1. 使用`openssl s_client -connect your-endpoint:8883`测试证书握手 2. 通过华为云设备调试台查看设备在线状态 3. 使用MQTT.fx工具对比连接参数 ### 常见问题排查 1. **证书验证失败** - 错误日志:`MQTT_EVENT_ERROR: Certificate verification failed` - 解决方案:检查证书有效期、完整性和赋值位置 2. **认证失败(5)** - 错误代码:5表示用户名密码错误 - 调试方法:输出生成的username/password与华为云计算器比对 3. **网络连接超时** - 确认防火墙开放8883端口 - 使用`ping`和`telnet`测试网络连通性 ### 相关技术参考 1. 华为云设备接入文档:https://support.huaweicloud.com/devg-iothub/iot_02_0089.html 2. ESP-MQTT官方示例:https://github.com/espressif/esp-idf/tree/master/examples/protocols/mqtt/tcp 3. Paho MQTT C库文档:https://www.eclipse.org/paho/files/mqttdoc/MQTTClient/html/index.html [^2]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值