如何去验证pan是否连接成功,如何清理DNS缓存

我在查看黄山派连接小智服务器的代码的时候发现黄山派无法实现断开蓝牙后自动重连小智服务器,于是我就创建了一个定时器通过解析dns来判断pan是否已经连接,但是在pan连接成功后手机端断开pan,dns会在没有pan连接的情况下成功解析小智服务器ip,我看了一些资料发现是dns缓存没有清理,我该如何清理dns缓存或者有没有更好的办法去验证pan重连成功

如果是设备端主动断开还可以去清手机的dns 缓存,发送对应的命令之后,在断开pan就可以了

但是如果是手机端主动断开,就没有机会发送清理的命令,只能手机端主动清理了呢

我这边主要的问题就是在pan断开,通过定时器重连手机端可以看到已连接,但是设备端无法确认pan是否已被连接(因为才pan重连的时候会触发connected和disconnected两个事件无法真正的确认pan是否已被连接),是否有更好的办法确认设备端已连接pan

看LWIP是看dhcp的state

好的,我这边尝试一下

额,找了一圈不知道该如何查看dhcp状态啊

在 lwIP 里,DHCP 状态保存在 netif->dhcp 结构里,头文件 lwip/dhcp.h 把全部状态列成了一个枚举:

c

复制

enum dhcp_state {
    DHCP_STATE_OFF          = 0,  /* 协议未启用 */
    DHCP_STATE_REQUESTING   = 1,  /* 正在发 DISCOVER / REQUEST */
    DHCP_STATE_INIT         = 2,  /* 刚初始化,等待第一次请求 */
    DHCP_STATE_REBOOTING    = 3,  /* 重启后验证旧 lease */
    DHCP_STATE_REBINDING    = 4,  /* 续租超时,向任何服务器重新请求 */
    DHCP_STATE_RENEWING     = 5,  /* 正常续租中 */
    DHCP_STATE_SELECTING    = 6,  /* 已收到 OFFER,还未选 IP */
    DHCP_STATE_CHECKING     = 7,  /* 拿到 IP,做 ARP 冲突检测 */
    DHCP_STATE_BOUND        = 8,  /* 绑定成功,地址可用 */
    DHCP_STATE_BACKING_OFF  = 9   /* 冲突后退避 */
};

因此“拿到有效地址”等价于:

c

复制

netif->dhcp != NULL && netif->dhcp->state == DHCP_STATE_BOUND

下面给出 3 种最常见的“检测”写法,按场景直接抄即可。


  1. 裸机 / 超级循环:轮询直到绑定

c

复制

#include "lwip/dhcp.h"
#include "lwip/netif.h"

extern struct netif gnetif;   /* 你的网卡实例 */

void wait_dhcp_or_die(void)
{
    /* 如果接口还没启动 DHCP,先启动 */
    if (gnetif.dhcp == NULL)
        dhcp_start(&gnetif);

    while (1) {
        if (gnetif.dhcp != NULL &&
            gnetif.dhcp->state == DHCP_STATE_BOUND) {
            printf("DHCP bound: %s\n", ip4addr_ntoa(&gnetif.ip_addr));
            break;
        }
        /* 喂 lwip 定时器,别忘调用 sys_check_timeouts() 或
           ethernetif_input() 等接收函数 */
        sys_check_timeouts();
        /* 非阻塞延时,让 CPU 喘口气 */
        HAL_Delay(10);
    }
}

  1. RTOS 任务:阻塞信号量,状态变化时 post

c

复制

#include "lwip/dhcp.h"
#include "lwip/netif.h"
#include "cmsis_os.h"        /* 以 CMSIS-RTOS2 为例 */

extern struct netif gnetif;
static osThreadId_t dhcp_task_id;

/* DHCP 状态回调,lwip 在每次状态切换时都会调用 */
void dhcp_status_cb(struct netif *netif)
{
    if (netif->dhcp != NULL &&
        netif->dhcp->state == DHCP_STATE_BOUND) {
        /* 通知等待任务 */
        osThreadFlagsSet(dhcp_task_id, 0x0001U);
    }
}

void dhcp_wait_task(void *arg)
{
    dhcp_task_id = osThreadGetId();

    dhcp_start(&gnetif);
    /* 注册回调 */
    netif_set_status_callback(&gnetif, dhcp_status_cb);

    /* 永久等事件 */
    osThreadFlagsWait(0x0001U, osFlagsWaitAny, osWaitForever);

    printf("DHCP success: %s\n", ip4addr_ntoa(&gnetif.ip_addr));
    /* 这里继续你的业务代码 … */
}

  1. 只想“看一眼”当前状态(调试 / 日志)

c

复制

const char *dhcp_state_str(struct netif *n)
{
    if (n->dhcp == NULL) return "OFF";
    switch (n->dhcp->state) {
    case DHCP_STATE_OFF:        return "OFF";
    case DHCP_STATE_INIT:       return "INIT";
    case DHCP_STATE_SELECTING:  return "SELECTING";
    case DHCP_STATE_REQUESTING: return "REQUESTING";
    case DHCP_STATE_CHECKING:   return "CHECKING";
    case DHCP_STATE_BOUND:      return "BOUND";
    case DHCP_STATE_RENEWING:   return "RENEWING";
    case DHCP_STATE_REBINDING:  return "REBINDING";
    default:                    return "UNKNOWN";
    }
}

/* 随时打印 */
printf("DHCP state: %s\n", dhcp_state_str(&gnetif));

易踩坑提醒

  1. 必须先 dhcp_start(&netif); 否则 netif->dhcp 是空指针。

  2. 一定要周期性调用 sys_check_timeouts()(裸机)或让 tcpip_thread 跑起来(RTOS),否则 DHCP 协议状态机不会跑。

  3. 如果启用了 LWIP_DHCP_DOES_ACD_CHECK(ARP 冲突检测),BOUND 之前会多一个 CHECKING 状态,耗时几百毫秒。

  4. 想判断“失败/超时”可以额外检查 netif->dhcp->tries 是否达到 DHCP_MAX_TRIES(默认 4),或者监听 DHCP_STATE_OFFdhcp_supplied_address() 返回 0。

照上面任意一种写法即可可靠地检测“DHCP 是否拿到有效地址”。

这个结构体没有dhcp参数

/**

  • 检查 DHCP 是否已提供 netif->ip_addr
  • @param netif 要检查的网络接口
  • @return 1 如果 DHCP 已提供 netif->ip_addr(状态为 BOUND 或 RENEWING 或 REBINDING),
  •     否则返回 0
    

*/
u8_t
dhcp_supplied_address(const struct netif *netif)
{
if ((netif != NULL) && (netif_dhcp_data(netif) != NULL))
{
struct dhcp *dhcp = netif_dhcp_data(netif);
return (dhcp->state == DHCP_STATE_BOUND) || (dhcp->state == DHCP_STATE_RENEWING) ||
(dhcp->state == DHCP_STATE_REBINDING);
}
return 0;
}

这个接口可以检查dhcp是否ready

我不知道这样写是否有问题,但是运行的时候报错了

目前这个功能还不支持,我们内部还在处理。

可还有其他的办法验证pan是否已连接

example/multimedia/lvgl/streaming_media/src/pan.c · 思澈科技/SiFli-SDK - 码云 - 开源中国

参考这里的例子怎么判断pan断开和链接

这个代码我研究过,也运行过,还是不行。我们的方案是蓝牙连接后开启pan定时连接,如果连接成功关闭连接定时器(连接小智服务器),失败重新开启连接定时器。但是pan在未开启的情况下如果执行bt_interface_conn_ext((char *)&g_bt_app_env.bd_addr, BT_PROFILE_PAN);函数,会连续触发BT_NOTIFY_PAN_PROFILE_CONNECTED和BT_NOTIFY_PAN_PROFILE_DISCONNECTED两个事件(间隔有歌几十毫秒),我在这两个事件里面做的pan断开重连和小智服务器连接。也就意味着断开如果pan断开或者未开启我会一直执行连接小智服务器的动作。

这个例子你是怎么操作有这个问题,是把手机pan关闭吗?

是的,手机端断开pan

你那边的操作场景是怎么样的,我这边断开pan之后重连没有一起出现connected 和 disconnected

[当前进展]

  • pan连接断开的消息是监听connected/disconnected
  • netif可以用是需要DHCP成功获取到ip地址
  • 麻烦参考监听到lwip link state up消息时,监听DHCP state上:
  • 需要写一个while 循环调用这个API,确认dhcp_supplied_address 返回值是否ok,ok才可以网络使用,如果超过30s获取不到,麻烦断开pan,重新连接

dhcp_supplied_address

你这个是定时发送pan连接,但是手机端没有打开pan开关的打印吗