larkguo@gmail.com
2007-05-26
目录
1 简介 (3)
2 Architecture (3)
3 数据结构 (6)
3.1 Pbuf (6)
3.2 Netbuf (7)
3.3 Netconn (8)
3.4 udp_pcb (10)
3.5 tcp_seg (10)
3.6 tcp_pcb (11)
3.7 tcp_pcb_listen (13)
3.8 Mbox (13)
3.8.1 tcpip_msg (14)
3.8.2 api_msg (14)
3.9 Socket (15)
3.10 定时 (16)
4 API (17)
4.1 TYPE 1 (19)
4.1.1 netconn_bind (20)
4.1.2 netconn_listen (20)
4.1.3 netconn_close (20)
4.2 TYPE 2 (20)
4.2.1 netconn_connect (21)
4.3 TYPE 3 (22)
4.3.1 netconn_send (22)
4.3.2 netconn_write (22)
4.4 TYPE 4 (23)
4.4.1 netconn_accept (23)
4.4.2 netconn_recv (23)
4.5 Server (24)4.6 Client (24)
5 流程 (25)
5.1 TCP (25)
5.1.1 TCP Send (25)
5.1.2 TCP Receive (26)
5.2 UDP (27)
6 主线程 (27)1简介
lwIP是瑞士计算机科学院(Swedish Institute of Computer Science)的Adam Dunkels等开发的一套用于嵌入式系统的开放源代码TCP/IP协议栈。Lwip既可以移植到操作系统上,又可以在无操作系统的情况下运行.
LwIP的特性如下:
z支持多网络接口下的IP转发
z支持ICMP协议
z包括实验性扩展的的UDP(用户数据报协议)
z包括阻塞控制,RTT估算和快速恢复和快速转发的TCP(传输控制协议)
z提供专门的内部回调接口(Raw API)用于提高应用程序性能
z可选择的Berkeley接口API(多线程情况下)
z在最新的版本中支持ppp
z新版本中增加了的IP fragment的支持.
z支持DHCP协议,动态分配ip地址.
z支持IPv6
2Architecture
3.1Pbuf
Pbuf是lwIP包的内部表示,被设计为最小化栈的特殊需要。Pbufs类似于BSD实现中的mbufs。Pbuf结构支持为包内容动态分配内存和让包数据驻留在静态内存中。Pbufs能被一个称为pbuf链的链接到一个链表中,以至一个包能跨越多个pbufs。
Pbufs有三种类型:PBUF_RAM,PBUF_ROM和PBUF_POOL。图1表示PBUF_RAM 类型,包含有存在内存中由pbuf子系统管理的包数据。图2显示了一个pbuf链表,第1个是PBUF_RAM类型,第2个是PBUF_ROM类型,意味着它包含有不被pubf子系统管理的内存数据。图3描述了PBUF_POOL,其包含有从固定大小pbuf池中分配来的pbuf。一个pbuf链可以包含多个不同类型的pbuf。
这三种类型有不同的用处。PBUF_POOL类型主要由网络设备驱动使用,因为分配单个pbuf 快速且适合中断句柄使用。PBUF_ROM类型由应用程序发送那些在应用程序内存空间中的
数据时使用。这些数据不会在pbuf递交给TCP/IP栈后被修改,因此这个类型主要用于当数据在ROM中时。PBUF_ROM中指向数据的头部被存在链表中其前一个PUBF_RAM类型的pbuf中,如图2所示。
PBUF_RAM类型也用于应用程序发送动态产生的数据。这情况下,pbuf系统不仅为应用程序数据分配内存,也为将指向(prepend)数据的头部分配内存。如图1所示。Pbuf系统不能预知哪种头部将指向(prepend)那些数据,只假定最坏的情况。头部的大小在编译时确定。
本质上,进来的pbuf是PBUF_POOL类型,而出去的pbuf是PBUF_ROM或PBUF_RAM类型。
从图1,图2可以看出pbuf的内部结构。Pbuf结构包含有两个指针,两个长度字段,一个标志字段,和一个参考计数。Next字段指向统一链表中的下一个pbuf。有效载荷指针指向该pbuf 中数据的起始点。Len字段包含有该pbuf数据内同的长度。Tot_len字段是当前pbuf和所有链表接下来中的len字段值的总和。简单说,tot_len字段是len字段及下一个pbuf中tot_len字段值的总和。Flags字段表示pbuf类型而ref字段包含一个参考计数。Next和payload字段是本地指针,其大小由处理器体系结构决定。两个长度字段是16位无符号整数,而flags和ref 字段都是4比特大小。Pbuf的总大小决定于使用的处理器体系结构。在32位指针和4字节校正的体系结构上,总大小是16字节,而在16位指针和1自己校正的体系结构上,总大小是9字节。
Pbuf模块提供了操作pbuf的函数。Pbuf_alloc()可以分配前面提到的三种类型的pbuf。Pbuf_ref()增加引用计数,pbuf_free()释放分配的空间,它先减少引用计数,当引用计数为0时就释放pbuf。Pbuf_realloc()收缩空间以使pbuf只占用刚好的空间保存数据。Pbuf_header()调整payload指针和长度字段,以使一个头部指向pbuf中的数据。Pbuf_chain()和pbuf_dechain()用于链表化pbuf。
3.2Netbuf
描述网络缓存的数据类型
3.3Netconn
描述网络连接的数据类型与socket一一对应
3.5tcp_seg
3.7tcp_pcb_listen
3.8Mbox
3.8.1tcpip_msg
TCPIP_MSG_API 表示从API (上层)来的包,包括api_msg中的api_msg_type所有类型的包; TCPIP_MSG_INPUT 表示从IP(下层)来的包.
3.8.2api_msg
3.9Socket
3.10定时
在tcp/ip协议中很多时候都要用到定时,定时的实现也是tcp/ip协议栈中一个重要的部分.lwip 中定时事件的数据结构如下.
struct sys_timeout {
struct sys_timeout *next;//指向下一个定时结构
u32_t time;//定时时间
sys_timeout_handler h;//定时时间到后执行的函数
void *arg;//定时时间到后执行函数的参数.
}
struct sys_timeout *next;
};
struct sys_timeouts lwip_timeouts[LWIP_TASK_MAX];
Lwip中的定时事件表的结构如下图,每个和tcp/ip相关的任务的一系列定时事件组成一个单向链表.每个链表的起始指针存在lwip_timeouts的对应表项中.
4API
TYPE 1
BIND, LISTEN, CLOSE TYPE 2
CONNECT
TYPE 3
SEND. WRITE
TYPE 4
ACCEPT, RECV
4.1TYPE 1
4.1.1netconn_bind
4.1.2netconn_listen
4.1.3netconn_close
4.2TYPE 2
4.2.1netconn_connect
在lwip实现中,应用层调用connect函数进行主动连接,在该函数内部实际上是生成一个消息发送给tcpip_thread线程,在此消息里包含了conn->mbox信号量句柄,然后,该函数阻塞等待在此信号量上。一旦底层完成三次握手,连接成功,就会触发TCP已连接事件TCP_EVENT_CONNECTED回调do_connect释放此信号量,connect随即退出阻塞。在应用层看来,connect一直阻塞到连接成功,如果不成功就返回-1。
connect运行在用户线程,实际连接运行在tcpip_thread线程,通过消息回调,使两个不同线程的函数建立了同步关系,虽然TCP协议时延动态范围很大,达到秒级,但这种消息驱动机制能很好地适应变化。
4.3TYPE 3
4.3.1netconn_send
4.3.2netconn_write
4.4TYPE 4
4.4.1netconn_accept
4.4.2netconn_recv
4.5Server
4.6Client
5流程
5.1TCP
5.1.1TCP Send
5.1.2TCP Receive
5.2UDP
6主线程
tcpip_thread是LwIP的主线程,整个tcp/ip协议栈都在同一个任务(tcpip_thread)中.