最近使用 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. Fiddler对安卓模拟器中的app抓包

    工具资源 Fiddler: https://www.telerik.com/download/fiddler Xposed Installer: https://repo.xposed.info/mo ...

  2. RT-Thread 运行时常见错误

    一.空线程栈较小 现象: 现象一: 现象二: 原因: 从RT-Thread文章中心可知,空闲线程是不能被挂起的,官方文档说明如下图所示: 注意:必须保证空闲线程的栈空间足够,否则空闲线程内存溢出后,也 ...

  3. ADV7123驱动VGA显示色条

    VGA显示色条-基于ADV7123 用ADV7123代替权电阻网络,执行数模转换,差别在于rgb都变成8位,显示的色彩更多.控制端口多了3个:像素时钟,复合同步信号(不用就置0),消隐信号. 相对权电 ...

  4. mysql如何优雅的备份数据

    MySQL 有多种备份方式,以下是几种常用的备份方式: 使用 mysqldump 命令备份数据 mysqldump 是 MySQL 自带的备份工具,可以备份指定数据库或表的数据为 SQL 文件.可以通 ...

  5. 密码学—DES加密的IP置换Python程序

    文章目录 IP初始置换与逆置换 编程想法 转二进制过程中的提取一些数据 64为一组 IP置换 IP逆置换 DES发明人 美国IBM公司W. Tuchman 和 C. Meyer1971-1972年研制 ...

  6. Ceph存储池管理

    目录 Ceph存储池 1. Ceph的存储流程 1. 数据写入 2. 数据读取 2. 资源池的配置 2.1 资源池创建 pgp是什么 (Placement Group for Placement pu ...

  7. 昇腾开发全流程 之 MindSpore华为云模型训练

    前言 学会如何安装配置华为云ModelArts.开发板Atlas 200I DK A2, 并打通一个训练到推理的全流程思路. 在本篇章,首先我们开始进入训练阶段! 训练阶段 A. 环境搭建 MindS ...

  8. Windows Server 2022 NTP服务器

    一.配置NTP服务器 配置NTP服务器,为客户端提供时间同步服务. 如果计算机是Active Directory域控制器,则NTP服务器功能已自动启动. 因此,下面的示例是计算机在工作组环境中启用NT ...

  9. 论GNU、Linux和GNU/Linux之间的关系

    相信很多人看到了这个标题就会产生疑问,这篇文章到底要讲什么东西?在回答这个问题之前,我先提出几个问题? 1. 什么是Linux? 2. 什么是GNU? 3. GNU/Linux是什么玩意儿? 在回答了 ...

  10. 010. Jenkins安装与插件管理

    jenkins安装 要求安装环境: 内存: 1G以上 cpu: 1核以上 1. 环境准备: 10.0.0.65 jenkins 10.0.0.66 gitlab 官方安装文档: https://jen ...