[STM32F7] STM32F767 基于 LWIP 实现 MQTT

[复制链接]
109|21
SocialButterfly 发表于 2026-8-8 10:39 | 显示全部楼层 |阅读模式

我刚接触 LWIP 和 MQTT。我想在 STM32F767 上基于 LWIP 实现 MQTT 功能。
以太网可以正常建立连接,ping 也能通。我调用`mqtt_client_connect`去连接服务器,
这里需要传入所要连接服务器的 IP 地址。我希望改用主机域名,而不是 IP 地址。
我该做哪些修改,才能直接使用类似 `"broker.mqttdashboard.com"` 这样的域名?
函数如下:

mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ip_addr, u16_t port, mqtt_connection_cb_t cb, void *arg,const struct mqtt_connect_client_info_t *client_info)

{{

err_t err;

size_t len;

u16_t client_id_length;

/* Length is the sum of 2+"MQTT", protocol level, flags and keep alive */

u16_t remaining_length = 2 + 4 + 1 + 1 + 2;

u8_t flags = 0, will_topic_len = 0, will_msg_len = 0;

LWIP_ASSERT("mqtt_client_connect: client != NULL", client != NULL);

LWIP_ASSERT("mqtt_client_connect: ip_addr != NULL", ip_addr != NULL);

LWIP_ASSERT("mqtt_client_connect: client_info != NULL", client_info != NULL);

LWIP_ASSERT("mqtt_client_connect: client_info->client_id != NULL", client_info->client_id != NULL);

if (client->conn_state != TCP_DISCONNECTED) {

  LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_client_connect: Already connected\n\r"));

  return ERR_ISCONN;

}

/* Wipe clean */

memset(client, 0, sizeof(mqtt_client_t));

client->connect_arg = arg;

client->connect_cb = cb;

client->keep_alive = client_info->keep_alive;

mqtt_init_requests(client->req_list);

/* Build connect message */

if (client_info->will_topic != NULL && client_info->will_msg != NULL) {

  flags |= MQTT_CONNECT_FLAG_WILL;

  flags |= (client_info->will_qos & 3) << 3;

  if (client_info->will_retain) {

   flags |= MQTT_CONNECT_FLAG_WILL_RETAIN;

  }

  len = strlen(client_info->will_topic);

  LWIP_ERROR("mqtt_client_connect: client_info->will_topic length overflow", len <= 0xFF, return ERR_VAL);

  LWIP_ERROR("mqtt_client_connect: client_info->will_topic length must be > 0", len > 0, return ERR_VAL);

  will_topic_len = (u8_t)len;

  len = strlen(client_info->will_msg);

  LWIP_ERROR("mqtt_client_connect: client_info->will_msg length overflow", len <= 0xFF, return ERR_VAL);

  will_msg_len = (u8_t)len;

  len = remaining_length + 2 + will_topic_len + 2 + will_msg_len;

  LWIP_ERROR("mqtt_client_connect: remaining_length overflow", len <= 0xFFFF, return ERR_VAL);

  remaining_length = (u16_t)len;

}

/* Don't complicate things, always connect using clean session */

flags |= MQTT_CONNECT_FLAG_CLEAN_SESSION;

len = strlen(client_info->client_id);

LWIP_ERROR("mqtt_client_connect: client_info->client_id length overflow", len <= 0xFFFF, return ERR_VAL);

client_id_length = (u16_t)len;

len = remaining_length + 2 + client_id_length;

LWIP_ERROR("mqtt_client_connect: remaining_length overflow", len <= 0xFFFF, return ERR_VAL);

remaining_length = (u16_t)len;

if (mqtt_output_check_space(&client->output, remaining_length) == 0) {

  return ERR_MEM;

}

client->conn = tcp_new();

if (client->conn == NULL) {

  return ERR_MEM;

}

/* Set arg pointer for callbacks */

tcp_arg(client->conn, client);

/* Any local address, pick random local port number */

err = tcp_bind(client->conn, IP_ADDR_ANY, 0);

if (err != ERR_OK) {

  LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_client_connect: Error binding to local ip/port, %d\n\r", err));

  goto tcp_fail;

}

LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_client_connect: Connecting to host: %s at port:%"U16_F"\n\r", ipaddr_ntoa(ip_addr), port));

/* Connect to server */

err = tcp_connect(client->conn, ip_addr, port, mqtt_tcp_connect_cb);

if (err != ERR_OK) {

  LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_client_connect: Error connecting to remote ip/port, %d\n\r", err));

  goto tcp_fail;

}

/* Set error callback */

tcp_err(client->conn, mqtt_tcp_err_cb);

client->conn_state = TCP_CONNECTING;

/* Append fixed header */

mqtt_output_append_fixed_header(&client->output, MQTT_MSG_TYPE_CONNECT, 0, 0, 0, remaining_length);

/* Append Protocol string */

mqtt_output_append_string(&client->output, "MQTT", 4);

/* Append Protocol level */

mqtt_output_append_u8(&client->output, 4);

/* Append connect flags */

mqtt_output_append_u8(&client->output, flags);

/* Append keep-alive */

mqtt_output_append_u16(&client->output, client_info->keep_alive);

/* Append client id */

mqtt_output_append_string(&client->output, client_info->client_id, client_id_length);

/* Append will message if used */

if ((flags & MQTT_CONNECT_FLAG_WILL) != 0) {

  mqtt_output_append_string(&client->output, client_info->will_topic, will_topic_len);

  mqtt_output_append_string(&client->output, client_info->will_msg, will_msg_len);

}

return ERR_OK;

tcp_fail:

tcp_abort(client->conn);

client->conn = NULL;

return err;

}


公羊子丹 发表于 2026-8-10 20:14 | 显示全部楼层
核心思路是先做DNS域名解析,lwIP自带dns_gethostbyname函数,解析出域名对应的ip_addr_t后再传给mqtt_client_connect,原生MQTT接口只认IP,没法直接塞域名。
周半梅 发表于 2026-8-10 20:15 | 显示全部楼层
你得先在lwipopts.h把LWIP_DNS宏打开,还要配置DNS服务器地址,比如8.8.8.8,不开启DNS功能的话,域名解析函数直接返回失败,走不通域名连接。
帛灿灿 发表于 2026-8-10 20:16 | 显示全部楼层
想问下你工程有没有跑FreeRTOS?DNS解析是异步回调,裸机得循环轮询解析状态,RTOS里可以用信号量等待解析完成,再执行MQTT连接。
童雨竹 发表于 2026-8-10 20:17 | 显示全部楼层
别直接修改mqtt_client_connect底层源码,建议封装一层上层函数,入参传域名字符串,内部先解析域名,解析成功再调用原生连接接口,后续升级lwIP不用改库。
万图 发表于 2026-8-10 20:18 | 显示全部楼层
踩坑提醒:F4内部Dcache会导致SD卡读写脏数据,挂载MSC前必须给SD读写缓冲区加__attribute__((align(32))),不然拷文件直接损坏。
Wordsworth 发表于 2026-8-10 20:19 | 显示全部楼层
调侃一句,刚接触lwIP MQTT基本都会卡在域名这块,原生接口设计就是只支持IP,不封装DNS,新手很容易误以为改个入参就能填域名。
Bblythe 发表于 2026-8-10 20:20 | 显示全部楼层
给你一套分步调试流程:先单独写测试代码调用dns_gethostbyname,打印解析出来的IP,解析正常再对接MQTT,拆分问题更容易定位故障。
Pulitzer 发表于 2026-8-10 20:21 | 显示全部楼层
注意DNS解析有超时,裸机主循环里持续调用dns_tmr轮询处理解析报文,只调用一次解析函数就等着,程序会一直卡在等待域名结果阶段。
Uriah 发表于 2026-8-10 20:22 | 显示全部楼层
如果后续要加TLS加密MQTT,域名解析逻辑不变,只是解析完IP后再开启tls客户端,DNS和MQTT是两套独立模块,互不冲突。
Clyde011 发表于 2026-8-10 20:23 | 显示全部楼层
很多人忽略DHCP,静态IP下必须手动填DNS服务器,DHCP自动获取会同步拿到DNS地址,你可以先切DHCP模式测试域名解析,排除DNS地址配置错误问题。
belindagraham 发表于 2026-8-11 13:01 | 显示全部楼层
QTT Keep-Alive时间建议设为60s, 防止中间路由器丢弃空闲连接。
alvpeg 发表于 2026-8-12 19:17 | 显示全部楼层
MQTT作为应用层协议,对内存和缓冲区有特定要求,默认配置可能不足。
jtracy3 发表于 2026-8-12 21:34 | 显示全部楼层
使用 STM32CubeMX 快速初始化
班杰明 发表于 2026-8-13 13:48 | 显示全部楼层
域名解析后要转换成IP地址,用dns_gethostbyname函数,然后传给mqtt_client_connect。记得DNS服务器配置正确,还有DNS解析超时问题别忽略。
loutin 发表于 2026-8-16 10:28 | 显示全部楼层
如何实现MQTT的TLS加密通信?需要哪些额外的代码修改?
闪烁黎明 发表于 2026-8-16 11:30 | 显示全部楼层
域名解析要用dns_gethostbyname,记得打开LWIP_DNS并配置DNS服务器,然后在connect函数里替换ip_addr为解析结果。
jackcat 发表于 2026-8-18 19:39 | 显示全部楼层
stm32-f767-ethernet-mqtt-demo
梦境漫游者 发表于 2026-8-19 13:03 | 显示全部楼层
DNS解析域名,调用dns_gethostbyname()获取IP地址,再传入mqtt_client_connect()。注意DNS解析可能超时,在裸机主循环里轮询处理解析报文。
pmp 发表于 2026-8-20 12:19 | 显示全部楼层
STM32F767如何用LWIP+MQTT+FreeRTOS+MQTTX?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

205

主题

205

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部
0