lwip网络接口netif

本文详细解析了LwIP环境中网络接口的表示方式,通过netif结构体展示了不同网卡的组织形式及关键成员作用。重点介绍了初始化过程,包括IP地址、掩码、网关的配置,以及与底层硬件交互的函数指针绑定。阐述了如何通过网络接口列表选择合适的网络路径,以及默认网络接口的设定和使用。深入探讨了从数据接收、IP到MAC地址转换、直至数据发送的底层流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一个系统中可能有多个网络接口,有可能是以太网,有可能是WiFi,也有可能是其他的网络接口。
在lwip中每一个网络接口都由一个netif结构体表示。表示不同网卡的netif结构体链接成一个链表。全局变量struct netif *netif_list指向该链表表头。
全局变量struct netif *netif_default指向的netif结构所表示的网卡为缺省网卡。在发送消息的时候,会首先会通过这个网卡,若是没有回应,再使用其他网卡。
在之前的移植实例中,因为只有一个以太网卡作为网络接口,所以网卡就用struct netif netif表示了。

struct netif定义如下
struct netif {
struct netif *next;
char name[2];
int num;
struct ip_addr ip_addr;
struct ip_addr netmask;
struct ip_addr gw;
void (* input)(struct pbuf *p, struct netif *inp);
int (* output)(struct netif *netif, struct pbuf *p,
struct ip_addr *ipaddr);
void *state;
};
(1) next
指向链表中下一个netif结构
(2) ip_addr、netmask 和 gw
这三个结构体成员分别用来存储本网卡的 IP 地址、子网掩码和网关。
(3) err_t (* input)(struct pbuf *p, struct netif *inp)
这个函数是用来接收底层硬件输入的数据包的。函数的返回值是 err_t 类型,它是由 LwIP 定义的一种用于表示操作成功、失败等参数的变量。函数的输入参数为 pbuf 类型的 p 指针和 netif 类型的 inp 指针,表示我们要接收 inp 网卡通过底层硬件接收到的数据包,并把数据包保存到结构体 p 中。
(4) err_t (* output)(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)
本成员也是一个函数指针,它指向一个用于 IP 层输出的函数。在 IP 层有数据包需要发送时,就通过该指针调用 output 函数。本函数输入参数有 netif、pbuf 和 ip_addr 三个参数,表示使用 netif 网卡、把 pbuf 结构体的内容发送到 IP 地址为 ip_addr 的设备中。 但由于在硬件底层收发数据时是使用 MAC 地址的,所以本函数把 IP 地址经过转化得到 MAC地址后,调用下一个成员——linkoutput 函数。
(5) err_t (* linkoutput)(struct netif *netif, struct pbuf *p)
这个函数指针是指向最底层的网卡发送数据包函数。它是被上面的 output 函数调用的。在 output 函数中的 pbuf 数据包实际上缺少了 MAC 包中的 DA 段(目标 MAC 地址),output 函数把它的输入参数 IP 地址转化成 MAC 地址后,添加到 pbuf 的 payload 成员,组成完整 MAC 包,再由本函数 linkoutput 输出到网络中。
(6) state
state 指针指向一用户感兴趣的信息,这部分可以由用户自行配置,也可以不使用。
(7) mtu
本成员记录了最大传输单元,我们知道 MAC 数据段的最大长度为 1500 字节,所以本成员我们一般会直接赋值为 1500。
(8) hwaddr_len 和 hwaddr[NETIF_MAX_HWADDR_LEN]
hwaddr_len 存储的是 MAC 地长度,hwaddr[]数组则存储了本网卡的 MAC 完整地址。
(9) flags
本成员保存了网卡允许使用的功能,如使用广播地址、ARP 功能等。
(10) name 和 num
name 用于保存网络接口的名字,可以自由设置,名字是两个字节的

网络接口的初始化过程,根据之前的移植工程的步骤(主要netcong.c中)

struct netif netif; //定义网卡netif结构体

struct ip_addr ipaddr;
struct ip_addr netmask;
struct ip_addr gw;

IP4_ADDR(&ipaddr, 192, 168, 1, 254); //ip
IP4_ADDR(&netmask, 255, 255, 255, 0); //掩码
IP4_ADDR(&gw, 192, 168, 1, 1);//网关

netif_add(&netif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &ethernet_input);
//将之前设定的ip,掩码,网关初始化初始化netif结构体,结构体相关成员设定。
//链路层输出函数ethernet_input函数(ethnetif.c)与绑定结构体成员函数指针input
//netif_add函数的还有一个功能是调用底层硬件初始化函数ethernetif_init(ethnetif.c )对底层硬件进行初始化,同时netif结构体的部分成员在这里初始化。ethernetif_init部分如下:
  netif->state = ethernetif;
  netif->name[0] = IFNAME0;//网络接口模块
  netif->name[1] = IFNAME1;
  netif->output = etharp_output; //将netif结构体的输出函数指正与etharp_output(etharp.c)绑定
  netif->linkoutput = low_level_output;//将netif结构体的arp连接输出指针与low_level_output(ethernetif.c)绑定
  ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
low_level_init(netif);//对网络模块进行初始化,具体会根据网络接口,之前的移植实例用的Enc28j60模块。该函数同时会将硬件地址赋值给netif 相关成员,netif结构体也被链入链表 netif_list。

netif_set_default(&netif);
//设定该网卡为默认网卡,全局变量netif_default指针指向该结构体
netif_set_up(&netif);//实现该接口

网络接口初初始化之后,除了节本的网络参数之外(ip,mac等)。
两个全局变量指针netif_list,netif_default的都指向了改网络接口节点。
IP 层有数据发送时,它首先会以 netif_list 为索引选择满足某个条件的网络接口发送数据包,但是,当找不到这样的接口时,协议栈就会调用缺省的网络接口直接发送数据包。

netif结构体相关函数指针成员都绑定了相关函数
netif->input = ethernet_input;
netif->output = etharp_output;
netif->linkoutput = low_level_output;

当网卡有接收到数据(查询或者中断的方式)的时候,调用netif->input即ethernet_input(ethnernetif.c)会根据不同的报文类型,会执行不同的动作,具体看函数源码。例如若是ETHTYPE_IP时ip报文的时候,则调用ip_input(p, netif)将发往ip,交由ip层处理。

若是ip层有数据需要发送出去,则调用netif->output即etharp_output(etharp_out.c)将数据发送到底层。

若是底层数据发送到网络接口上发送出去,则调用netif->linkoutput 即low_level_output(ethnernetif.c)将数据通过网卡发送出去。






<think>好的,我需要回答用户关于LWIP_NETIF_LOOPBACK的定义和使用场景的问题。首先,我需要回忆一下LwIP中有关网络接口netif)的结构和功能。根据用户提供的引用内容,netif结构体用于描述每个网络接口的属性,包括IP地址、子网掩码、网关等。引用[3]提到每个网卡对应一个netif结构体,并且在启用DHCP后,相关信息会存储在其中。 接下来,用户提到的LWIP_NETIF_LOOPBACK应该与环回接口有关。环回接口在计算机网络中通常用于本地通信,允许应用程序在同一台设备上进行内部数据传输,而无需经过物理网络。在LwIP中,环回接口的实现可能涉及特定的配置选项或结构体。 根据引用[2],提到有一个静态的loop_netif变量,这可能是环回接口的实例。此外,netif结构体中的函数指针如netif_input_fn和netif_output_fn可能用于处理环回接口的数据输入和输出。需要确认LWIP_NETIF_LOOPBACK是否为编译时的宏定义,用于启用或配置环回接口功能。 使用场景方面,环回接口常用于本地测试,例如TCP/IP堆栈的自测、无需外部网络连接的应用程序开发等。例如,当开发一个客户端和服务器端都在同一设备上的应用时,使用环回接口可以避免依赖外部网络环境。 最后,需要确保引用的信息正确对应到用户提供的参考资料,特别是引用[2]中提到的loop_netif和相关的函数指针,以及引用[3]中关于netif结构体的作用。可能还需要查阅LwIP的官方文档或源代码来确认LWIP_NETIF_LOOPBACK的具体定义和使用方式,但根据现有引用,可以推断其基本功能和使用场景。</think>### LWIP_NETIF_LOOPBACK 定义与使用场景 #### 1. **定义** **LWIP_NETIF_LOOPBACK** 是 LwIP 协议栈中用于配置环回接口(Loopback Interface)的编译选项。 - **功能**:启用后,系统会创建一个虚拟网络接口(通过 `loop_netif` 结构体实现),允许数据包在本地设备内部直接回环传输,无需经过物理网络设备[^2][^3]。 - **实现方式**:在代码中,环回接口通过静态变量 `loop_netif` 定义,并绑定特定的输入/输出函数(如 `netif_input_fn` 和 `netif_output_fn`),用于处理本地数据包的收发[^2]。 #### 2. **使用场景** - **本地通信测试**:允许应用程序通过 TCP/IP 协议栈与本机其他服务通信(如客户端与服务器在同一设备)。 - 示例:使用 `127.0.0.1` 或 `localhost` 地址进行 HTTP 请求测试。 - **协议栈自检**:验证 LwIP 内部数据处理逻辑的正确性,无需依赖外部网络环境。 - **无物理网络依赖的开发**:在无网卡或网络未配置时,仍可通过环回接口调试网络功能。 #### 3. **关键代码结构** 环回接口的初始化与数据流处理通常涉及以下部分: ```c // 环回接口静态实例 static struct netif loop_netif; // 初始化函数(需在系统启动时调用) void netif_loop_init(void) { netif_add(&loop_netif, NULL, NULL, NULL, NULL, netif_loopif_init, netif_input); netif_set_link_up(&loop_netif); } // 数据包输入函数(模拟接收) err_t loopif_input(struct pbuf *p, struct netif *inp) { return netif_loop_output(inp, p, NULL); } ``` #### 4. **配置选项** - **启用环回接口**:需在 `lwipopts.h` 中定义 `LWIP_NETIF_LOOPBACK=1`。 - **队列深度控制**:通过 `LWIP_LOOPBACK_MAX_PBUFS` 设置环回队列缓存的数据包数量,避免内存耗尽[^2]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值