最近正初学LwIP,走了很多弯路,费时费力却不讨好,目前仍在研究中,下面是一点心得,供没接触过网络的人参考,也但愿高手指点指点其中的错误或者正在研究的朋友一块儿交流交流。我以为首先应找一个实例运行起来,结合网上的资料看源代码,这样效果会好不少,既有一个直观、实在的感性认识,又能够及时验证所学习的理论。这几篇不深刻研究代码,只按照实际的收发过程的顺序介绍协议栈的功能结构,并且只介绍TCP/IP/ARP等相关部分,只为达到最快入门。另外,对术语不做解释,可参考TCP/IP协议卷一或Google之。html
操做平台:网络
平台无关,无操做系统的裸机环境下实现数据结构
参考资料:函数
(1)TCP/IP协议详解(卷一)学习
(2)Lwip协议详解(做者:老纳五木) 下载:http://wenku.baidu.com/view/8e7a7fafd1f34693daef3e9f.html操作系统
(3)Design and Implementation of the LwIP TCP/IP Stack3d
废话说了好多,从最起始的接收部分开始吧!接收首先调用ethernetif_input(&netif),这个函数可放在一个进程去查询,也可中断实现。netif是咱们所使用的网络接口的数据结构,一个数据结构对应一个实际的物理网卡,如有多个则由链表将它们组织起来,其定义在netif.h中,数据结构以下:指针
struct netif {
struct netif *next;//下一个netif结构指针htm
struct ip_addr ip_addr;//IP地址
struct ip_addr netmask;//子网掩码
struct ip_addr gw;//网关接口
err_t (* input)(struct pbuf *p, struct netif *inp);//指向一个IP层接收数据包的函数
err_t (* output)(struct netif *netif, struct pbuf *p,struct ip_addr *ipaddr);//指向一个IP层发送数据包的函数
err_t (* linkoutput)(struct netif *netif, struct pbuf *p);//指向一个底层的发数数据包函数
void *state;//目前没什么用
u8_t hwaddr_len;//MAC地址长度
u8_t hwaddr[NETIF_MAX_HWADDR_LEN];//MAC地址
u16_t mtu;//单次传送的最大字节数
u8_t flags;//网卡的状态标志
char name[2];//网络接口的名字,可表明不一样的类别
u8_t num;//可用来区分两相同类别网络接口
};
这样ethernetif_input的参数&netif就是咱们实际的物理网卡,使用前必定要定义和初始化,初始化主要由netif_add()完成。ethernetif_input作了什么工做呢?(1)首先调用了low_level_input()函数,这个函数是真正的、与实际硬件相关的接收函数,随硬件不同而各不相同,但最终都会建立pbuf内存,而且将接收的以太网数据包放入由pubf管理的内存中;(2)而后,ethernetif_input函数调用netif->input(),处理刚放进内存的数据包。而netif->input()根据数据包的类型(eth_hdr->type)进行散转,若是是ARP包,则调用etharp_arp_input()传至ARP模块;若是是IP包,则调用ip_input()进入IP层。
pbuf是实现以太网数据包管理的数据结构,其定义在在pbuf.h中:
struct pbuf {
struct pbuf *next;//指向下一个pbuf
void *payload;//指向该pbuf管理的数据的起始位置
u16_t tot_len;//当前pbuf以后的全部有效数据的总长度
u16_t len; //当前pbuf中有效数据的长度
u8_t type;//pbuf的类型
u8_t flags;//不知道有什么用
u16_t ref;//当前pbuf被引用的次数,删除pbuf时会用到
};
另外,正如前面所说,pbuf及所管理内存的创建是在low_level_input()过程当中。pbuf中的payload项指向咱们收到的以太网数据包所存放的位置,而以太网数据包的包头便用的是eth_hdr数据结构来描述的,其定义在etharp.h中:
PACK_STRUCT_BEGIN
struct eth_hdr {
PACK_STRUCT_FIELD(struct eth_addr dest);//目标MAC地址
PACK_STRUCT_FIELD(struct eth_addr src);//源MAC地址
PACK_STRUCT_FIELD(u16_t type);//数据包类型
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
上面的PACK_STRUCT_xxx是与编译器字对齐相关的宏定义,先不用去管它。netif->input()就是根据该数据据构的type类型决定下一步将数据传入ARP模块仍是送入IP层。
(未完待续)