当前位置: 首页 > news >正文

lwIP——4 网络接口

1.lwIP网络接口

网络接口(网卡):个人理解是处理网络层数据传输关系的接口(tcp/ip协议栈中的网络接口层部分),直接与硬件平台打交道

lwIP协议栈支持多种不同的网络接口(网卡),由于网卡是直接和硬件平台打交道,硬件不同则处理也是不同的,所以由用户提供最底层的接口函数,lwIP提供统一的接口,但是底层的实现需要用户自己去完成(ethernetif.c) 

在lwIP中每一个网卡都由一个netif 结构体来表示,这些结构体描述了各个网卡的底层实现函数及状态,并以链表形式链接起来 

netif 屏蔽了硬件接口的差异,完成了对不同网络接口的抽象

流程示例(发送数据):

  1. 网络层准备数据:网络层根据上层应用需求,准备好要发送的数据,如组装 IP 数据包等。
  2. 统一接口传递:网络层调用 ethernet.c 中ethernet_output函数,将数据传递到下层。(封装:目的 MAC 地址、源 MAC 地址、帧类型)
  3. netif 结构体处理ethernet_output函数将数据发送给 netif 结构体,netif 结构体对数据进行一些适配处理,为发送到具体物理接口做准备。
  4. 底层文件与物理接口发送:ethernetif.c 的linkoutput函数从 netif 结构体获取数据,按照物理接口(如 WIFI、以太网接口)的要求进行最后的封装等操作,然后通过物理接口将数据发送到网络中。(也就是调用 low_level_output 把 pbuf 数据包拷贝到以太网发送描述符管理的 Buffer 当中,并调用函数 HAL_ETH_TransmitFrame 发送此帧)

 

 


2.lwIP的netif结构体

这些成员变量是根据相关网卡的特性,针对性填写

struct netif { struct netif *next; 				/* 指向下一个节点的指针 */ ip_addr_t ip_addr; 					/* 设置网卡的IP地址、子网页码及网关地址 */ ip_addr_t netmask; ip_addr_t gw; netif_input_fn input; 				/* 指向数据包输入函数 */ netif_output_fn output; 	/* 指向数据包待发送函数 ----检测目标IP地址的MAC地址等操作 */netif_linkoutput_fn linkoutput; 		/* 指向数据包输出函数 */netif_status_callback_fn link_callback; /* 链接状态回调函数 */ void *state; 						/* 虚拟网卡状态 */ u16_t mtu; 						    /* 最大传输单元 */ u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; 	/* 网卡的MAC地址 */ u8_t hwaddr_len; 					/* MAC地址长度 */u8_t flags; 						/* 虚拟网卡的标志符 */ char name[2]; 						/* 网卡的名称 */ /*................*/ };

 


 3. netif 相关函数

lwIP网络接口函数

描述

netif_init()

虚拟网卡初始化(lwip_init()

netif_add()

添加一个虚拟网卡

netif_remove()

移除一个虚拟网卡

netif_set_default()

设置默认虚拟网卡(用于未知的数据包)

…………………..

…………………..

全局变量 struct netif *netif_list:指向该链表表头 

全局变量 struct netif *netif_default:指向的netif结构所表示的网卡为缺省网卡。(在发送消息的时候,会首先会通过这个网卡,若是没有回应,再使用其他网卡)

3.1 netif_add()函数

struct netif *netif_add( struct netif    *netif,const ip4_addr_t    *ipaddr,const ip4_addr_t    *netmask,const ip4_addr_t    *gw,void    *state,netif_init_fn    init,netif_input_fn    input){// 清空网络接口的 IP 地址、子网掩码和网关地址信息,将其初始化为零ip_addr_set_zero_ip4(&netif->ip_addr);ip_addr_set_zero_ip4(&netif->netmask);ip_addr_set_zero_ip4(&netif->gw);// 将网络接口的输出函数初始化为空 IP4 输出函数,作为默认的输出处理方式netif->output = netif_null_output_ip4;// 初始化网络接口的最大传输单元(MTU)为 0,MTU 表示该网络接口一次能传输的最大数据长度netif->mtu = 0;// 初始化网络接口的标志位为 0,标志位可用于表示网络接口的各种状态netif->flags = 0;// 将网络接口的客户端数据数组清零,客户端数据可用于存储用户自定义的与该网络接口相关的数据memset(netif->client_data, 0, sizeof(netif->client_data));// 将用户传入的自定义状态数据指针赋值给网络接口的 state 字段,方便后续使用netif->state = state;// 为当前网络接口分配一个唯一的编号,netif_num 可能是一个全局变量用于记录网络接口编号netif->num = netif_num;// 将用户传入的网络接口输入处理函数指针赋值给网络接口的 input 字段,用于处理接收到的数据包netif->input = input;// 调用 netif_set_addr 函数设置网络接口的 IP 地址、子网掩码和网关地址// 如果传入的参数为 NULL,则保持之前清零时的零值netif_set_addr(netif, ipaddr, netmask, gw);// 调用用户提供的网络接口初始化函数对网络接口进行进一步的初始化操作// 如果初始化函数返回值不为 ERR_OK,表示初始化失败if (init(netif) != ERR_OK) {// 初始化失败,返回 NULL 表示网络接口添加失败return NULL;}// 将当前网络接口添加到全局网络接口列表的头部// 先将当前网络接口的 next 指针指向原来的网络接口列表头netif->next = netif_list;// 再将全局网络接口列表头指针指向当前网络接口,完成添加操作netif_list = netif;// 调用 mib2_netif_added 函数,该函数可能用于更新 MIB(管理信息库)相关信息,以反映新网络接口的添加mib2_netif_added(netif);// 调用 netif_invoke_ext_callback 函数触发网络接口添加的外部回调函数// 通知其他模块网络接口已成功添加netif_invoke_ext_callback(netif, LWIP_NSC_NETIF_ADDED, NULL);// 网络接口添加成功,返回指向该网络接口结构体的指针return netif;
}

 

3.2 netif_set_default() 函数

该函数就是设置某一个 netif 结构体为默认的网卡

// 定义 netif_set_default 函数,用于设置默认网络接口
void netif_set_default(struct netif *netif) {if (netif == NULL) {/* 删除默认路由 */mib2_remove_route_ip4(1, netif);} else {/* 添加默认路由 */mib2_add_route_ip4(1, netif);}// 选择指定的网络接口作为默认网络接口netif_default = netif; 
}// 以下是使用 netif_set_default 函数的示例代码
int main() {struct netif xnetif;ip4_addr_t ipaddr, netmask, gw;// 假设这里初始化 IP 地址、子网掩码和网关地址// 例如:IP4_ADDR(&ipaddr, 192, 168, 1, 100);IP4_ADDR(&netmask, 255, 255, 255, 0);IP4_ADDR(&gw, 192, 168, 1, 1);// 通过 netif_add 函数,将网络接口添加到链表中netif_add(&xnetif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &tcpip_input);// 注册默认的网络接口netif_set_default(&xnetif);return 0;
}

http://www.lryc.cn/news/527095.html

相关文章:

  • pytest自动化测试 - pytest夹具的基本概念
  • FreeRtos的使用教程
  • yolov11 解读简记
  • 实验二 数据库的附加/分离、导入/导出与备份/还原
  • Kafka常见问题之 `javax.management.InstanceAlreadyExistsException`
  • 性能测试丨JVM 性能数据采集
  • 计算机图形学实验练习(实验1.2-4.1AND补充实验12)
  • JWT实现单点登录
  • 云计算的概念与特点:开启数字化时代的新篇章
  • salesforce中如何获取一个profile的18位id
  • Vue 3 中的标签 ref 与 defineExpose:模板引用与组件暴露
  • FLTK - FLTK1.4.1 - demo - adjuster.exe
  • 单路由及双路由端口映射指南
  • 专为课堂打造:宏碁推出三款全新耐用型 Chromebook
  • 云计算架构学习之LNMP架构部署、架构拆分、负载均衡-会话保持
  • Python案例--暂停与时间格式化
  • 【javaweb项目idea版】蛋糕商城(可复用成其他商城项目)
  • git gui 笔记
  • 使用 Docker 运行 Oracle Database 23ai Free 容器镜像并配置密码与数据持久化
  • PyQt6医疗多模态大语言模型(MLLM)实用系统框架构建初探(下.代码部分)
  • salesforce公式字段 ISBLANK 函数和 <> NULL的区别
  • 微服务学习-服务调用组件 OpenFeign 实战
  • 关于安卓greendao打包时报错问题修复
  • Ansible自动化运维实战--通过role远程部署nginx并配置(8/8)
  • RGB 转HSV空间颜色寻找色块
  • Spring Boot - 数据库集成04 - 集成Redis
  • C++红黑树详解
  • 与机器学习相关的概率论重要概念的介绍和说明
  • 60.await与sleep的原理分析 C#例子 WPF例子
  • 数据库连接池是如何工作的?