最近使用 STM32 测试了一下 lwip 和 esp8266 的网络连接问题,使用 RTThread 的自动网卡时,发现不能很好的自动切换默认网卡,不能满足需求,所以自己简单的改了一下。

一、准备材料

  • MCU:STM32F103ZT6
  • RTThread:5.0.2
  • 工具:RTThread studio
  • 网络芯片:DM9000(FSMC连接)
  • WIFI:ESP8266(uart连接)

二、测试现象

  • 如果默认网卡断开是,无其他网卡联网时,其他网卡重新联网,不会自动切换默认网卡
  • 初始化时,如果默认网卡为初始成功,即时存在能联网的网卡时,也不会切换默认网卡

三、问题原因

遇到问题的时候,我们首先查看一下官方的说明文档: https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/netdev/netdev

找到默认网卡的说明,如下图所示:



从图中不难看出,他只有网卡从 up → down 的时候,才会去切换状态,所以也能解释上面我测试到的现象了

四、解决办法

这里有两个办法可以解决,方式一,直接就该源码;方式二,从新添加相应的处理程序,如下所示:

方式一

程序源码的文件是 rt-thread/components/net/netdev/src/netdev.c,

  1. 先来看一下自动切换网卡的实现方式, 程序如下

    /* Change to the first link_up network interface device automatically */
    static void netdev_auto_change_default(struct netdev *netdev)
    {
    struct netdev *new_netdev = RT_NULL; if (netdev->flags & NETDEV_FLAG_LINK_UP)
    {
    if (!(netdev_default->flags & NETDEV_FLAG_LINK_UP))
    {
    netdev_set_default(netdev);
    }
    return;
    }
    if (rt_memcmp(netdev, netdev_default, sizeof(struct netdev)) == 0)
    {
    new_netdev = netdev_get_first_by_flags(NETDEV_FLAG_LINK_UP);
    if (new_netdev)
    {
    netdev_set_default(new_netdev);
    }
    }
    }

    程序中不难看出切换网卡的思路,确实很厉害,代码也比较简洁,所以切换部分的代码没有问题

  2. 调用的自动切换部分的程序

    /**
    * This function will set network interface device status.
    * @NOTE it can only be called in the network interface device driver.
    *
    * @param netdev the network interface device to change
    * @param is_up the new status
    */
    void netdev_low_level_set_status(struct netdev *netdev, rt_bool_t is_up)
    {
    if (netdev && netdev_is_up(netdev) != is_up)
    {
    if (is_up)
    {
    netdev->flags |= NETDEV_FLAG_UP;
    }
    else
    {
    netdev->flags &= ~NETDEV_FLAG_UP; #ifdef NETDEV_USING_AUTO_DEFAULT
    /* change to the first link_up network interface device automatically */
    netdev_auto_change_default(netdev);
    #endif /* NETDEV_USING_AUTO_DEFAULT */
    } /* execute network interface device status change callback function */
    if (netdev->status_callback)
    {
    netdev->status_callback(netdev, is_up ? NETDEV_CB_STATUS_UP : NETDEV_CB_STATUS_DOWN);
    }
    }
    } /**
    * This function will set network interface device active link status.
    * @NOTE it can only be called in the network interface device driver.
    *
    * @param netdev the network interface device to change
    * @param is_up the new link status
    */
    void netdev_low_level_set_link_status(struct netdev *netdev, rt_bool_t is_up)
    {
    if (netdev && netdev_is_link_up(netdev) != is_up)
    {
    if (is_up)
    {
    netdev->flags |= NETDEV_FLAG_LINK_UP; #ifdef RT_USING_SAL
    /* set network interface device flags to internet up */
    if (netdev_is_up(netdev) && !ip_addr_isany(&(netdev->ip_addr)))
    {
    sal_check_netdev_internet_up(netdev);
    }
    #endif /* RT_USING_SAL */
    }
    else
    {
    netdev->flags &= ~NETDEV_FLAG_LINK_UP; /* set network interface device flags to internet down */
    netdev->flags &= ~NETDEV_FLAG_INTERNET_UP; #ifdef NETDEV_USING_AUTO_DEFAULT
    /* change to the first link_up network interface device automatically */
    netdev_auto_change_default(netdev);
    #endif /* NETDEV_USING_AUTO_DEFAULT */
    } /* execute link status change callback function */
    if (netdev->status_callback)
    {
    netdev->status_callback(netdev, is_up ? NETDEV_CB_STATUS_LINK_UP : NETDEV_CB_STATUS_LINK_DOWN);
    }
    }
    }

    从程序中不难看出,它是只有当网络状态为 down 的时候,才去调用切换网络状态函数

  3. 解决办法

    只需要将 netdev_low_level_set_link_status 函数中的调用位移,移除 down 的判断条件即可解决这个问题。这个问题解决很简单,但是为啥会是这样的设计我还没弄明白,也能是开发人员粗心了(按理说不应该),也有可能是另有深意,但是不满足我得需求,所以还是需要更改一下。这里我没有改源程序,而是从新写了一个函数去实现的,具体流程如下

方式二

通过提供的 API 重写了一下默认网卡切换的方法,程序如下

#include <rtthread.h>
/* 当需要网卡操作是,需要包含这两个头文件 */
#include <arpa/inet.h>
#include <netdev.h> #define DBG_TAG "app_net_monitor"
#include <rtdbg.h> typedef struct net_device_info
{
const char *name; // 设备名称
struct netdev *dev; // 网络设备指针
} net_device_info_t; /* 初始网卡设备,第一个为默认网卡 */
static net_device_info_t net_device[] =
{
{"e0", RT_NULL},
{"esp0", RT_NULL}
}; /* 默认网卡设备 */
struct netdev *network_default = RT_NULL; rt_uint16_t net_dev_number = sizeof(net_device)/sizeof(net_device_info_t); /**
* @brief 自动更改为第一个link_up网络接口设备
*
* @param netdev 网络设备对象
*/
static void network_auto_change_default(struct netdev *netdev)
{
struct netdev *new_netdev = RT_NULL; if (netdev->flags & NETDEV_FLAG_LINK_UP)
{
if (!(network_default->flags & NETDEV_FLAG_LINK_UP))
{
netdev_set_default(netdev);
network_default = netdev;
}
return;
}
if (rt_memcmp(netdev, network_default, sizeof(struct netdev)) == 0)
{
new_netdev = netdev_get_first_by_flags(NETDEV_FLAG_LINK_UP);
if (new_netdev)
{
netdev_set_default(new_netdev);
network_default = new_netdev;
}
}
} /**
* @brief 网络设备状态回调函数
*
* @param netdev 网络设备对象
* @param type 网络状态类型
*/
void network_status_callback(struct netdev *netdev, enum netdev_cb_type type)
{
switch (type)
{
/* 网络断开 */
case NETDEV_CB_STATUS_LINK_DOWN:
network_auto_change_default(netdev);
break; /* 网络连接 */
case NETDEV_CB_STATUS_INTERNET_UP:
network_auto_change_default(netdev);
break; default:
break;
}
} /**
* @brief 返回设备联网状态
*
* @return RT_EOK 表示网络连接
*/
rt_bool_t network_is_up()
{
return netdev_is_link_up(network_default);
} /**
* @brief 初始化自动网卡设置
*
*/
static int app_network_init(void)
{ for (int i = 0; i < net_dev_number; i++)
{
/* 获取网卡设备 */
net_device[i].dev = netdev_get_by_name(net_device[i].name);
if (net_device[i].dev == RT_NULL)
{
LOG_E("not find network interface device name(%s).\n", net_device[i].name);
continue;
} /* 设置网络设备状态变化的回调函数 */
netdev_set_status_callback(net_device[i].dev, network_status_callback); /* 设置一个默认网卡 */
if (network_default == RT_NULL)
{
network_default = net_device[i].dev;
netdev_set_default(network_default);
} } return RT_EOK;
} INIT_APP_EXPORT(app_network_init);

RTThread 自动网卡使用问题的更多相关文章

  1. 从个人的角度谈谈本次GNTC大会的收获

    GNTC资料:from sdnlab 从个人的角度谈谈本次大会的收获 从本次大会的主题演讲来看,目前SDN.NFV的最前沿已经不再像五年前持观望态度以及探讨,各大运营商.各大厂商已经将SDN.NFV具 ...

  2. vmvare入门(1)使用移动,不要使用复制

    1.复制虚拟机会产生新的自动网卡,原来的 System Eth0废了? 2.xftp链接的时候,要选择sftp方式连接,utf8编码.

  3. RT-Thread--内核基础

    内核介绍 内核处于硬件层之上,内核部分包括内核库.实时内核实现. 实时内核的实现包括:对象管理.线程管理及调度器.线程间通信管理.时钟管理及内存管理等等,内核最小的资源占用情况是 3KB ROM,1. ...

  4. Debian、kali类虚拟机网络设置

    Linux发行版分类 先说一下Linux发行版的分类,因为不同的发行版,各自设置的网络的方式就不相同, - 我常用的Linux发行版 -- Debian --- debian --- ubuntu - ...

  5. [dpdk][kernel][driver] 如何让DPDK的UIO开机自动加载到正确的网卡上

    0. 前言 开了虚拟机,开始dpdk之前,我每天都干这几件事: [root@dpdk potatos]# modprobe uio [root@dpdk potatos]# insmod /root/ ...

  6. 解决网卡无法自动获取ip的办法

    解决网卡无法自动获取IP址的方法          为了省钱或者一户多机,很多人都购买宽带路由器共享上网.在架设路由上网的时候,有些“师傅”可能不懂或是偷懒,开启了宽带路由器的DHCP( Dynami ...

  7. Centos 7开启网卡打开DHCP自动获取IP

    在Windows10上安装了CentOS7的Hyper-V虚拟机. 虽然配置了可访问外网的网卡(Win8.1 Hyper-V 共享本机IP上网),但是默认安装的CentOS是没有开启配置网卡信息的,也 ...

  8. CentOS7或CentOS8 开机自动启用网卡的设置方法

    sudo nano /etc/sysconfig/network-scripts/ifcfg-enp0s3(p0s3是网卡,名字不同环境会有差异,输入时可按tab自动补全.) 将最后一行的 ONBOO ...

  9. 【linux】centos6.9设置etc0网卡开机自动获取ip

    在vm新安装的centos系统中,一般选择NAT来设置和主机共享局域网,通过ifconfig etc0 192.168.xx.xx 这种作法机器重启之后就会失效,所以可以使用更改文件的方式完成设置ce ...

  10. 解决eth0网卡无法自动加载的问题

    问题:输入ifup eth0显示无法加载网卡所在的文件 解决办法: vi /etc/rc.d/rc.local 最后一行加入: ifup eth0 然后重启虚拟机即可解决问题. 本文为博主原创文章,未 ...

随机推荐

  1. 聊聊 dotnet 7 对 bool 与字符串互转的底层性能优化

    本文也叫 跟着 Stephen Toub 大佬学性能优化系列.大家都知道在 .NET 7 有众多的性能优化,其中就包括了对布尔和字符串互转的性能优化.在对布尔和字符串的转换的性能优化上,有着非常巧妙的 ...

  2. win10 uwp 选择文本转语音的机器人

    在 UWP 里,可以非常方便将某个文本转换为音频语音,转换时,将会根据输入的内容以及本机所安装的语言库选择一位机器人帮忙将输入的文本转换为语音.本文来告诉大家如何切换文本转语音的机器人,例如从默认的女 ...

  3. dotnet 在 WPF 里显示数学 π 的颜色

    有逗比小伙伴问我,数学的 π 视觉效果是啥.于是我就来写一个逗比的应用将 π 的颜色在 WPF 应用画出来.原理就是读取 π 的小数点后的数值,然后使用逗比算法转换为 RGB 颜色像素,接着将这些像素 ...

  4. 2018-8-10-win10-uwp-App-to-app-communication-应用通信

    title author date CreateTime categories win10 uwp App-to-app communication 应用通信 lindexi 2018-08-10 1 ...

  5. 魔方OA 数据字典

    https://gitee.com/mojocube/mc-oa/blob/master/Data/%E6%95%B0%E6%8D%AE%E5%BA%93%E8%84%9A%E6%9C%AC.sql ...

  6. vue--v-if和v-show的区别(个人项目中的理解应用)

    在面试的时候,一道vue基础到不能再基础的面试题叫做v-if与v-show的区别,当然答案网上一搜一大堆,基本两句话就能说明: 1.相同点:都是根据指令是否渲染该组件 2.不同点:v-if仅重新渲染当 ...

  7. 二、Doris架构原理

    Doris是一个MPP的OLAP系统,以较低的成本提供在大数据集上的高性能分析和报表查询功能. MPP (Massively Parallel Processing),即大规模并行处理.简单来说,MP ...

  8. 【python爬虫案例】用python爬取百度的搜索结果!2023.3发布

    目录 一.爬取目标 二.展示结果数据 三.编写爬虫代码 3.1 请求头和cookie 3.2 分析请求地址 3.3 分析页面元素 3.4 获取真实地址 3.5 保存结果数据 四.同步讲解视频 五.附完 ...

  9. 01、Windows 排查

    Windows 分析排查 分析排查是指对 Windows 系统中的文件.进程.系统信息.日志记录等进行检测,挖掘 Windows 系统中是否具有异常情况 1.开机启动项检查 一般情况下,各种木马.病毒 ...

  10. GitLab 管理 NuGet 包

    1 概览 在服务器上构建项目时,需要引用 nuget.org 之外的包,如公司内部开发的.第三方未发布到 nuget.org 上的.怎么办? GitLab 提供了 Package Registry 来 ...