You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP32基于Rust实现MQTT连接AWS IoT Core失败的问题求助

ESP32基于Rust实现MQTT连接AWS IoT Core失败的问题求助

我现在遇到了一个ESP32用Rust连接AWS IoT Core的卡壳问题,先跟大家说下背景:我知道目前用Rust在ESP32上开发还不算主流,遇到坑是正常的,但这次实在找不到方向了,希望有经验的朋友能指点下。

能正常工作的部分

  • 代码可以正常烧录并在ESP32上运行
  • 能正确加载src/certificates目录下的证书文件
  • WiFi连接正常(用的是普通WPA Personal,没有复杂的企业级配置)
  • 连接自建MQTT broker或者broker.emqx.io时,发布和订阅主题都没问题,哪怕带上证书也能正常工作

不能正常工作的部分

  • 无法通过MQTT连接AWS IoT Core并进行发布/订阅操作,这一步需要证书,我自认为证书处理是没问题的(下面会贴代码)

额外信息

  • 证书文件是从AWS下载后重命名的:
    • server.cert.crt 对应AWS提供的root-CA.crt
    • client.cert.pem 对应my-thing-rev1.cert.pem
    • client.private.key 对应my-thing-rev1.private.key
  • 我还拿到了my-thing-rev1.public.key和my-thing-rev1-Policy,但我觉得这两个暂时用不上?
  • 我知道这种直接嵌入证书的方式不是生产环境的正确做法,这只是一个简单的POC

核心代码

use embedded_svc::httpd::Result;
use embedded_svc::mqtt::client::{Connection, MessageImpl, QoS};
use esp_idf_svc::mqtt::client::{EspMqttClient, MqttClientConfiguration};
use esp_idf_svc::tls::X509;
use esp_idf_sys::EspError;

// 其他无关导入省略

extern crate dotenv_codegen;
extern crate core;

const AWS_IOT_ENDPOINT: &str = dotenv!("AWS_IOT_ENDPOINT");
const AWS_IOT_CLIENT_ID: &str = dotenv!("AWS_IOT_CLIENT_ID");
const AWS_IOT_TOPIC: &str = dotenv!("AWS_IOT_TOPIC");

fn main() -> Result<()> {
    esp_idf_sys::link_patches();

    // 其他代码省略
    let mqtt_client: EspMqttClient<ConnState<MessageImpl, EspError>> = test_mqtt_client()?;
    // 更多代码省略

    Ok(())
}

fn convert_certificate(mut certificate_bytes: Vec<u8>) -> X509<'static> {
    // 追加NUL字符
    certificate_bytes.push(0);

    // 转换证书格式
    let certificate_slice: &[u8] = unsafe {
        let ptr: *const u8 = certificate_bytes.as_ptr();
        let len: usize = certificate_bytes.len();
        mem::forget(certificate_bytes);
        slice::from_raw_parts(ptr, len)
    };

    // 返回正确格式的证书
    X509::pem_until_nul(certificate_slice)
}

fn test_mqtt_client() -> Result<EspMqttClient<ConnState<MessageImpl, EspError>>> {
    info!("About to start MQTT client");

    let server_cert_bytes: Vec<u8> = include_bytes!("certificates/server.cert.crt").to_vec();
    let client_cert_bytes: Vec<u8> = include_bytes!("certificates/client.cert.pem").to_vec();
    let private_key_bytes: Vec<u8> = include_bytes!("certificates/client.private.key").to_vec();

    let server_cert: X509 = convert_certificate(server_cert_bytes);
    let client_cert: X509 = convert_certificate(client_cert_bytes);
    let private_key: X509 = convert_certificate(private_key_bytes);

    // TODO: 修复错误 `E (16903) esp-tls-mbedtls: mbedtls_ssl_handshake returned -0x7280`
    let conf = MqttClientConfiguration {
        client_id: Some(AWS_IOT_CLIENT_ID),
        crt_bundle_attach: Some(esp_idf_sys::esp_crt_bundle_attach),
        server_certificate: Some(server_cert),
        client_certificate: Some(client_cert),
        private_key: Some(private_key),
        ..Default::default()
    };

    let (mut client, mut connection) =
        EspMqttClient::new_with_conn(AWS_IOT_ENDPOINT, &conf)?;

    info!("MQTT client started");

    // 必须立即启动消息循环,否则后续的subscribe和publish无法工作
    // 注意:如果使用另一个构造函数 `EspMqttClient::new`,不需要单独开线程,消息会通过回调处理
    // 但回调里处理消息也不能阻塞太久
    thread::spawn(move || {
        info!("MQTT Listening for messages");
        while let Some(msg) = connection.next() {
            match msg {
                Err(e) => info!("MQTT Message ERROR: {}", e),
                Ok(msg) => info!("MQTT Message: {:?}", msg),
            }
        }
        info!("MQTT connection loop exit");
    });

    client.subscribe(AWS_IOT_TOPIC, QoS::AtMostOnce)?;
    info!("Subscribed to all topics ({})", AWS_IOT_TOPIC);

    client.publish(
        AWS_IOT_TOPIC,
        QoS::AtMostOnce,
        false,
        format!("Hello from {}!", AWS_IOT_TOPIC).as_bytes(),
    )?;
    info!("Published a hello message to topic \"{}\".", AWS_IOT_TOPIC);

    Ok(client)
}

设备运行日志(关键部分)

I (16913) esp32_aws_iot_with_std: About to start MQTT client
I (16923) esp32_aws_iot_with_std: MQTT client started
I (16923) esp32_aws_iot_with_std: MQTT Listening for messages
I (16933) esp32_aws_iot_with_std: MQTT Message: BeforeConnect
I (17473) esp-x509-crt-bundle: Certificate validated
E (19403) MQTT_CLIENT: mqtt_message_receive: transport_read() error: errno=119  # <- 这是关键错误
E (19403) MQTT_CLIENT: esp_mqtt_connect: mqtt_message_receive() returned -1
E (19413) MQTT_CLIENT: MQTT connect failed
I (19413) esp32_aws_iot_with_std: MQTT Message ERROR: ESP_FAIL
I (19423) esp32_aws_iot_with_std: MQTT Message: Disconnected
E (19433) MQTT_CLIENT: Client has not connected
I (19433) esp32_aws_iot_with_std: MQTT connection loop exit
...
Error: ESP_FAIL

我查了下这个错误,看起来像是接收数据的缓冲区满了,但不确定具体原因,也不知道怎么解决。

另外,用mosquitto命令行工具是可以正常连接并发送消息到AWS IoT的:

mosquitto_pub -h my.amazonawsIoT.com --cafile server.cert.crt --cert client.cert.pem --key client.private.key -i basicPubSub -t my/topic -m 'test'

我尝试过的解决方法

  • 一开始以为是Flash空间不够,但我的设备是ESP32 Devkitc v4(修订版1),Flash是4MB,当前程序只占用了32.63%(1347344/4128768字节),应该没问题
  • 后来意识到缓冲区是在RAM里,我的设备RAM应该是320KB,但不确定具体占用情况
  • 尝试修改MQTT客户端配置里的buffer_size和out_buffer_size,试了各种数值(比如50、10),但要么还是原来的错误,要么出现新错误:
    E (18303) MQTT_CLIENT: Connect message cannot be created
    E (18303) MQTT_CLIENT: MQTT connect failed
    E (18313) MQTT_CLIENT: Client has not connected
    
    而且我找不到文档说明这个数值的单位是比特、千比特还是字节,完全摸不着头脑。

有没有朋友遇到过类似的问题?这个错误到底是不是缓冲区的问题?如果是的话,该怎么调整?或者有没有其他我没考虑到的点?

备注:内容来源于stack exchange,提问作者Nico V

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 15:37:36