对你了解应用程序、协议栈、驱动、控制器之间的关系有所帮助。如果包中有数据(有可能
只是握手协议数据,没有应用数据),应用程序需要尽快的从 buffer 中取走数据处理或者
复制到第二缓存中去稍后处理,因为只有一个全局 buffer,不然的话可能会被下一个包覆盖
掉。直到数据被应用程序处理完之前,包缓存是不会被新包覆盖的(?),如果应用程序正
在进行处理数据,后续的包必需进行硬件级或者驱动级的排队。大多数的以太网控制器有一
个硬件缓存至少可容纳 4 个最大尺寸的以太网帧。如果缓存满了,后续的包就会丢弃。只
有当打开多个连接时,才可能出现这种情形以致影响性能。原因在于 uIP 通告了一个很小的
接收窗口(窗口,协议中的概念),也就意味着每个连接上只有个 TCP 分组。
在 uIP 中,用于接收包的全局包缓冲 buffer 同样适用于数据报头的发送。假如应用程序需
要发送动态大小的数据,可能会使用不作为报头临时缓存的全局缓存的一部分。为了发送数
据,应用程序会向协议栈传递指向数据的指针和数据的长度。一旦 TCP/IP 报头生成并复制
到全局缓存后,设备驱动就会发送出报头和数据(数据不是被一层层的协议头封装的么)。
如果需要重传数据只能重新生成数据了,而不会有队列等待的。
uIP 的内存消耗很大程度上取决于实现其的设备上应用程序的情况。内存配置决定了系统所
能处理的流量值和同时在线连接的数量。在发送一个超大邮件的同时还运行着大量动态网页
请求的 web 服务器所消耗的内存肯定要比只运行简单 Telnet 服务器的大的多。仅有 200 字
节 RAM 的设备上运行 uIP 也是可以的,只是这种配置极大的影响了网络的吞吐以及可同时
在线的连接数。
1.4
应用程序接口
(API)
应用程序接口 (API) 定义了应用程序如何和 TCP/IP 协议栈进行交互。最长使用的 API 是
大多数 unix 类系统中 BSD 风格的套接字 API,而且对 Windows 下的 WinSock API 也有着
巨大的影响。因为套接字 API 使用 stop-and-wait 语义,因而需要多任务操作系统的支持。
这样一来,繁重的任务管理以及上下文切换,任务栈分配对于 uIP 的目标群体来说是不现实
的,也就是说 BSD 套接字对于 uIP 的不合适的。
相反,uIP 使用事件驱动接口,有事件发生时相应的应用程序(UIP_APPCALL( ),如无标
注下文中的应用程序均指 UIP_APPCALL 宏对应的函数)会被调用。一个被实现为 C 函数
运行在 uIP 顶层的应用程序会被 uIP 调用来响应特定的事件。就像 telnet.h 文件中的:
#ifndef UIP_APPCALL
#define UIP_APPCALL telnetd_app
#endif
当接收到数据、成功将数据发送到连接的另一端、建立了一新连接亦或是重传了数据时,
uIP 就会调用相应的应用程序(uip_process->UIP_APPCALL();)。应用程序同时会周期的
轮询以查看是否有新数据到达。由应用程序映射不同服务到不同端口和连接,对于栈只提供
一个回调函数。也就是说尽可能的减少协议栈的响应时间,既便是低端的系统也能做到快速
响应到来的数据或者连接请求,处理数据就推到上层去吧