LWIP协议栈架构与设计解析word资料13页.docx
- 文档编号:23966591
- 上传时间:2023-05-23
- 格式:DOCX
- 页数:16
- 大小:25.02KB
LWIP协议栈架构与设计解析word资料13页.docx
《LWIP协议栈架构与设计解析word资料13页.docx》由会员分享,可在线阅读,更多相关《LWIP协议栈架构与设计解析word资料13页.docx(16页珍藏版)》请在冰豆网上搜索。
LWIP协议栈架构与设计解析word资料13页
LWIP协议栈及接口提取
与当今“教师”一称最接近的“老师”概念,最早也要追溯至宋元时期。
金代元好问《示侄孙伯安》诗云:
“伯安入小学,颖悟非凡貌,属句有夙性,说字惊老师。
”于是看,宋元时期小学教师被称为“老师”有案可稽。
清代称主考官也为“老师”,而一般学堂里的先生则称为“教师”或“教习”。
可见,“教师”一说是比较晚的事了。
如今体会,“教师”的含义比之“老师”一说,具有资历和学识程度上较低一些的差别。
辛亥革命后,教师与其他官员一样依法令任命,故又称“教师”为“教员”。
Version1.0
这个工作可让学生分组负责收集整理,登在小黑板上,每周一换。
要求学生抽空抄录并且阅读成诵。
其目的在于扩大学生的知识面,引导学生关注社会,热爱生活,所以内容要尽量广泛一些,可以分为人生、价值、理想、学习、成长、责任、友谊、爱心、探索、环保等多方面。
如此下去,除假期外,一年便可以积累40多则材料。
如果学生的脑海里有了众多的鲜活生动的材料,写起文章来还用乱翻参考书吗?
2012/06/20
一般说来,“教师”概念之形成经历了十分漫长的历史。
杨士勋(唐初学者,四门博士)《春秋谷梁传疏》曰:
“师者教人以不及,故谓师为师资也”。
这儿的“师资”,其实就是先秦而后历代对教师的别称之一。
《韩非子》也有云:
“今有不才之子……师长教之弗为变”其“师长”当然也指教师。
这儿的“师资”和“师长”可称为“教师”概念的雏形,但仍说不上是名副其实的“教师”,因为“教师”必须要有明确的传授知识的对象和本身明确的职责。
版本
1.0
姓名
部门
邮件
作者
雷岩
Leiyan3521@163
审阅
版本历史
版本
日期
修订
姓名
Rev1.0
2011/11/07
FirstDraft
leiyan
一、LWIP介绍
首先说明一下,这篇文档的主要目的是提取网络发送和接收数据的函数接口。
然后用我们自己的驱动网卡的接口函数替代程序中的接口。
如果对LWIP协议栈本身没什么兴趣的,可以跳过第一、二、三章,直接阅读第四章,使用我们的接口代替第四章的接口就行了。
写第一、二、三章的主要目的是为了方便理解数据的发送和接收在LWIP协议栈中是如何进行处理的。
这便于我们理解提取出来的接口。
LWIP是瑞典计算机科学院开发的一套用于嵌入式系统的开放源代码的轻量级的TCP/IP协议栈。
传统的,或者说是典型的TCP/IP协议族的设计都是按照分层的思想来设计的。
这样设计有个好处,就是每层相对于其他层独立,代码方便理解。
缺点就是,每层之间进行数据交互的时候必须要进行复制,而数据的复制是很耗时的,这就降低了实时性。
LWIP采用了一种不同的设计方式来实现TCP/IP协议族。
LWIP各层之间没有明显的界限,各层之间都可以访问到共享在内存中的数据。
因为各层都可以访问共享内存,所以这就避免了内存复制产生的性能损失。
但是并不是说LWIP就没有分层的概念了。
只不过LWIP各层都是逻辑意义上的层。
每个协议都以模块的形式被实现。
而这些模块就共同组成了LWIP整体。
下面一章将分析LWIP的源码,结合源码介绍这些模块。
了解各个协议是怎么通过模块被实现的。
其中这里最主要的是TCP协议模块的实现。
TCP协议在LWIP协议栈中占得比例最大,有将近一半的代码是专门用来实现TCP协议的。
所以重点会分析TCP协议。
并且无线音频项目采用的也是TCP协议传输数据。
LWIP逻辑上被分为四个层:
应用层,传输层,网络层和网络接口层。
如下图1.1所示:
图1.1LWIP协议栈的分层模型
应用层主要是使用LWIP协议栈开发相应的网络通信程序。
LWIP主要提供了三种接口供用户使用。
三种接口分别为RAWAPI,NetconnAPI和BSDSocketAP。
其中RAWAPI主要是采用回调函数的方式来完成数据的发送和接收,RAWAPI接口写的应用程序与LWIP协议栈处在同一个进程(或者称任务)中。
NetconnAPI和BSDSocketAP工作于多线程方式中,要使用者两种接口,必须有多任务的操作系统的支持。
这次项目采用的接口是RAWAPI。
关于RAWAPI接口如何写应用层程序,另写了一个专门的文档介绍。
这里不列出。
传输层。
我们最熟悉的TCP协议,UDP协议,以及我们使用ping命令时采用的ICMP协议都处在这一层。
这一层提供了一些专门的接口,用于处理与应用层和网络层的数据传送(注明,这里说的数据传送并不是指数据的拷贝。
事实上,LWIP协议栈使用的是内存共享技术,各层都能访问这段共享内存,各层传递的就是数据结构指针,所以LWIP协议栈降低了内存复制所产生的性能损失)。
关于这层函数,会在下面进行具体说明。
网络层主要的协议是IP协议。
这一层主要是对底层接收的数据包进行发送,转发,丢弃组合等功能。
网络接口层是和底层硬件驱动交互的层。
我们所需要提取的网络接口就在这一层。
二、LWIP源码分析
1.LWIP协议栈的架构
LWIP协议栈源码的架构如下图2.1所示:
图2.1LWIP协议栈源码架构
api目录:
应用程序接口文件,包括netconn和BSD2种API。
这个文件夹主要是为了方便应用程序编写而为应用层提供的API接口。
core目录:
ICMP,IP,TCP,UDP协议的实现文件,以及一些辅助函数,LWIP实现的核心代码。
其中这个文件夹里面实现TCP协议的代码量几乎占了整个lwip协议栈的一半。
重点会讨论TCP协议。
在此也可以简单看出LWIP协议栈没有严格区分传输层和网络层,因为传输层的代码和网络层的代码放在一个文件夹里实现了。
目录里还提供了RAWAPI接口的实现。
RAWAPI接口和上面两种接口一样,都是为了方便应用程序编写而为应用层提供的API接口。
include目录:
主要是LWIP协议栈使用的自定义的一些头文件。
netif目录:
这个目录里主要实现的是ARP协议。
当然还有一些PPPOE等协议。
当然PPPOE协议不是我们所关心的。
port目录:
最后写这个目录,主要是因为这个目录是我们最终所要修改的一个目录。
可以看到此目录下包含一个ethernetif.c文件。
这个文件提供了与底层网络驱动的一个接口。
我们要实现与自己的网络接口驱动交互,必须修改这个文件里的接口,使这些接口为上层屏蔽细节信息。
2.各个文件夹介绍
【1】api目录,如图2.2
图2.2api目录下的文件列表
这个文件夹下面主要提供的是netconnAPI和BSDsocketAPI。
这些接口不是我们所要关心的。
所以直接忽略。
我们使用下面文件夹里提供的RAWAPI接口。
【2】core目录,如图2.3
图2.3core目录下的文件列表
这个文件下下面,ipv6文件夹和snmp文件夹我们不需要关心。
主要关心的文件有icmp.c
Ip.cip_addr.cip_frag.cdhcp.cinit.cmem.cmemp.cnetif.cpbuf.c
Raw.ctcp.ctcp_in.ctcp_out.cudp.c
【3】include目录,如图2.4
图2.4include目录下的文件列表
这个文件夹下面主要包括所有.c文件用到的头文件。
Ipv6文件夹我们不必关心。
【4】netif目录,如图2.5
图2.5netif目录下的文件列表
这个文件夹下面主要关心etharp.c这个文件其余的不必关心。
其中文件夹PPP是关于点对点协议的,不必关心
【5】port目录,如图2.6
图2.6port目录下的文件列表
这个文件夹下面关于arch目录,这个目录是移植时候主要修改的目录。
这个目录下包含的是与体系结构相关的一些定义等。
FreeRTOS这个文件夹不需要关心,因为这是基于实时操作系统的,而我们现在做的项目是基于单任务的,无需操作系统的支持。
Standalone这个文件夹下面的ethernetif.c中给出的驱动接口。
我们为自己的网络接口设计的驱动程最终用来代替这个文件里的接口。
上面所有文件大致描述了LWIP协议栈的几个模块:
配置模块、初始化模块、NetIf模块、Mem(memp)模块、netarp模块、ip模块、udp模块、icmp模块、igmp模块和dhcp模块。
由于篇幅限制,不能对每个源文件都做介绍。
只对我们感兴趣的模块的源文件做相应的介绍。
3.模块及源文件介绍
【1】配置模块
配置模块的文件主要包含在include/lwip/opt.h里(这里及下文所指的路径均为相对路径)。
配置模块通过各种宏定义的方式对系统、子模块进行了配置。
比如,通过宏,配置了mem管理模块的参数。
该配置模块还通过宏,配置了协议栈所支持的协议簇,通过宏定制的方式,决定了支持那些协议。
*LWIP_ARP==1:
EnableARPfunctionality.
#ifndefLWIP_ARP
#defineLWIP_ARP1
#endif
截取一段代码说明问题。
上面的代码表示配置的时候支持ARP(地址解析协议)协议族,此代码下面对ARP协议族进行一些其他的配置。
【2】初始化模块
初始化模块(这里主要讲的是TCP协议的初始化模块)主要在文件api/tcpip.c中。
贴上源代码
void
tcpip_init(void(*initfunc)(void*),void*arg)
lwip_init();
tcpip_init_done=initfunc;
tcpip_init_done_arg=arg;
mbox=sys_mbox_new(TCPIP_MBOX_SIZE);
#ifLWIP_TCPIP_CORE_LOCKING
lock_tcpip_core=sys_sem_new
(1);
#endif/*LWIP_TCPIP_CORE_LOCKING*/
sys_thread_new(TCPIP_THREAD_NAME,tcpip_thread,NULL,TCPIP_THREAD_STACKSIZE,TCPIP_THREAD_PRIO);
这个初始化模块是如此的重要,以至于我们可以说这是整个程序的核心。
首先调用lwip_init()初始化了所有的子模块。
然后调用sys_thread_new()启动了协议栈管理进程。
所有的程序就在tcpip_thread这个进程里运行(这里说的是使用RAWAPI接口的情况)。
【3】NetIf模块
netif模块是非常重要的一个模块,主要是因为里面有一个netif的结构体。
Netif模块为协议栈与底层驱动的接口模块,其将底层的一个网口设备描述成协议栈的一个接口设备(netinterface)。
这个接口设备就是用上面说的netif结构体来描述。
所以说neitif结构体很重要。
Netif模块主要文件为core/netif.c和include/lwip/netif.h。
structnetif{
/**pointertonextinlinkedlist*/
structnetif*next;
/**IPaddressconfigurationinnetworkbyteorder*/
structip_addrip_addr;
structip_addrnetmask;
structip_addrgw;
/**Thisfunctioniscalledbythenetworkdevicedriver
*topassapacketuptheTCP/IPstack.*/
err_t(*input)(structpbuf*p,structnetif*inp);
/**ThisfunctioniscalledbytheIPmodulewhenitwants
*tosendapacketontheinterface.Thisfunctiontypically
*firstresolvesthehardwareaddress,thensendsthepacket.*/
err_t(*output)(structnetif*netif,structpbuf*p,
structip_addr*ipaddr);
/**ThisfunctioniscalledbytheARPmodulewhenitwants
*tosendapacketontheinterface.Thisfunctionoutputs
*thepbufas-isonthelinkmedium.*/
err_t(*linkoutput)(structnetif*netif,structpbuf*p);
#ifLWIP_NETIF_STATUS_CALLBACK
/**Thisfunctioniscalledwhenthenetifstateissettoupordown
void(*status_callback)(structnetif*netif);
#endif/*LWIP_NETIF_STATUS_CALLBACK*/
#ifLWIP_NETIF_LINK_CALLBACK
/**Thisfunctioniscalledwhenthenetiflinkissettoupordown
void(*link_callback)(structnetif*netif);
#endif/*LWIP_NETIF_LINK_CALLBACK*/
/**Thisfieldcanbesetbythedevicedriverandcouldpoint
*tostateinformationforthedevice.*/
void*state;
#ifLWIP_DHCP
/**theDHCPclientstateinformationforthisnetif*/
structdhcp*dhcp;
#endif/*LWIP_DHCP*/
#ifLWIP_AUTOIP
/**theAutoIPclientstateinformationforthisnetif*/
structautoip*autoip;
#endif
#ifLWIP_NETIF_HOSTNAME
/*thehostnameforthisnetif,NULLisavalidvalue*/
char*hostname;
#endif/*LWIP_NETIF_HOSTNAME*/
/**maximumtransferunit(inbytes)*/
u16_tmtu;
/**numberofbytesusedinhwaddr*/
u8_thwaddr_len;
/**linklevelhardwareaddressofthisinterface*/
u8_thwaddr[NETIF_MAX_HWADDR_LEN];
/**flags(seeNETIF_FLAG_above)*/
u8_tflags;
/**descriptiveabbreviation*/
charname[2];
/**numberofthisinterface*/
u8_tnum;
#ifLWIP_SNMP
/**linktype(from"snmp_ifType"enumfromsnmp.h)*/
u8_tlink_type;
/**(estimate)linkspeed*/
u32_tlink_speed;
/**timestampatlastchangemade(up/down)*/
u32_tts;
/**counters*/
u32_tifinoctets;
u32_tifinucastpkts;
u32_tifinnucastpkts;
u32_tifindiscards;
u32_tifoutoctets;
u32_tifoutucastpkts;
u32_tifoutnucastpkts;
u32_tifoutdiscards;
#endif/*LWIP_SNMP*/
#ifLWIP_IGMP
/*ThisfunctioncouldbecalledtoaddordeleteaentryinthemulticastfiltertableoftheethernetMAC.*/
err_t(*igmp_mac_filter)(structnetif*netif,structip_addr*group,u8_taction);
#endif/*LWIP_IGMP*/
#ifLWIP_NETIF_HWADDRHINT
u8_t*addr_hint;
#endif/*LWIP_NETIF_HWADDRHINT*/
#ifENABLE_LOOPBACK
/*Listofpacketstobequeuedforourselves.*/
structpbuf*loop_first;
structpbuf*loop_last;
#ifLWIP_LOOPBACK_MAX_PBUFS
u16_tloop_cnt_current;
#endif/*LWIP_LOOPBACK_MAX_PBUFS*/
#endif/*ENABLE_LOOPBACK*/
这个结构体里所有的成员的作用都已经注释了,这里我们只关心两个成员:
err_t(*input)(structpbuf*p,structnetif*inp);
err_t(*output)(structnetif*netif,structpbuf*p,
当收到一个信息包时,设备驱动程序调用input指针指向的函数。
网络接口通过output指针连接到设备驱动。
这个指针指向设备驱动中一个向物理网络
发送信息包的函数,当信息包被发送时由IP层调用。
这个字段由设备驱动的初始设置函数
填充。
也就是说,当我们从网络上接收一个数据的时候我们调用input函数指针指向的函数进行数据接收的处理。
当我们要向网络中发送一个数据时,我们调用output函数指针指向的那个函数进行数据的发送工作。
因为这个netif结构体是与底层驱动进行交互的。
所以input和output函数指针是直接指向网络驱动收发接口函数的。
回到netif.c文件中,netif.c文件通过链表的方式描述了系统中的所有网口设备。
因为系统中可能会有很多网络设备。
【4】Mem(memp)模块
其实mem和memp管理的是不同类型的内存,但都属于内存管理。
所以放在了一起。
Mem模块同一管理了协议栈使用的内容缓冲区,并管理pbuf结构以及报文的字段处理。
主要的文件包括mem.c、memp.c、pbuf.c。
这里我们所要关心的是内存管理单元所管理的pbuf结构体。
typedefenum{
PBUF_RAM,/*pbufdataisstoredinRAM*/
PBUF_ROM,/*pbufdataisstoredinROM*/
PBUF_REF,/*pbufcomesfromthepbufpool*/
PBUF_POOL/*pbufpayloadreferstoRAM*/
}pbuf_type;
如上所示,pbuf有四种类型(但是文档中只介绍了三种类型)。
关于这四种类型的pbuf有什么区别请参考相应的文档,一句话说明四者的不同,主要是pbuf结构体中存放的数据的位置不同。
一句话说明pbuf类型的选择。
当接收网络数据包时,我们选择的pbuf是PBUF_POOL类型的。
至于网络数据包的发送,根据自己的实际情况自己选择。
structpbuf*pbuf_alloc(pbuf_layerl,u16_tsize,pbuf_typetype);
voidpbuf_realloc(structpbuf*p,u16_tsize);
u8_tpbuf_header(structpbuf*p,s16_theader_size);
voidpbuf_ref(structpbuf*p);
voidpbuf_ref_chain(structpbuf*p);
u8_tpbuf_free(structpbuf*p);
u8_tpbuf_clen(structpbuf*p);
voidpbuf_cat(structpbuf*head,structpbuf*tail);
voidpbuf_chain(structpbuf*head,structpbuf*tail);
structpbuf*pbuf_dechain(structpbuf*p);
err_tpbuf_copy(structpbuf*p_to,structpbuf*p_from);
u16_tpbuf_copy_partial(structpbuf*p,void*dataptr,u16_tlen,u16_toffset);
err_tpbuf_take(structpbuf*buf,constvoid*dataptr,u16_tlen);
structpbuf*pbuf_coalesce(structpbuf*p,pbuf_layerlayer);
这是对pbuf结构体进行操作的函数。
【5】netarp模块
netarp模块是处理arp协议的模块,主要源文件为netif/etharp.c。
其主要入口函数为:
err_tethernet_input(structpbuf*p,structnetif*netif)
该入口函数通过判断输入报文p的协议类型来决定是按照arp协议进行处理还是将该报文提交到IP协议。
如果报文是arp报文,该接口则调用etharp_arp_input,进行arp请求处理。
如果是ip报文,该接口就调用etharp_ip_input进行arp更新,并调用ip_input接口,将报文提交给ip层。
在该模块中,创建了设备的地址映射arp表,并提供地址映射关系查询接口。
同时还提供了arp报文的发送接口。
如下:
err_tetharp_output(structnetif*netif,structpbuf*q
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- LWIP 协议 架构 设计 解析 word 资料 13