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.crtclient.cert.pem对应my-thing-rev1.cert.pemclient.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
相关产品推荐
相关产品推荐

