使用lwip协议的Raw API工作模式

 

 
lwip RawApi 数据发送2009-05-11 23:29       今天调试程序,使用lwip协议的Raw API工作模式,做了一个简单的客户/服务器系统。服务器运行FPGA上,使用Powerpc405处理器,32Kcache,64M内存,无操作系统。客户端运行在x86机器,安装Linux操作系统。服务器接收数据没问题,100M网卡下速度约为5MB,其中包括将数据从pbuf中copy至应用程序内存,如果不添加copy操作,大约能达到8MB的传输速度。
 
      数据的发送存在问题,一开始数据完全无法发送,通过GDB跟踪调试一阶段后,发现跟踪很困难,因为代码太多,而且在EDK中通过GDB调式也很麻烦。最后直接启动了Lwip的调试功能,将协议处理的每一步都打印出来,才发现错误:TCP控制管理块PCB中的send_buf值为0,每次发送的时候都会因为发送缓冲区为0而推出。通过追踪发现,send_buf的值由opt.h中TCP_SEND_BUF定义,而opt.h中TCP_SEND_BUF由lwipops.h中的TCP_SEND_BUF确定,而lwipops.h中由xilekd_lwipopts.h定义,这里的TCP_SEND_BUF由用户从EDK人机交互目录中设定:定义为65536。
 
#ifndef TCP_SEND_BUF
 
#define TCP_SEND_BUF 32768
 
#endif
 
lwipops.h中的TCP_SEND_BUF由xiledk_lwipopts.h
 
我在EDK的Lwip设置中,将这个值设置为65536,但是从实际来看,这个设置没有完全起作用,因此将设置去掉,TCP_SEND_BUF自动恢复为32768,数据发送成功。通过查看pcb的定义可知pcb中send_buf为u16类型,即为unsigned short,65536超出其表示范围。
 
本次的调试过程中,跟我感触最深的是Lwip协议栈的Debug功能,启动Debug参数之后,Lwip将协议栈中每一步的关键信息都打印出来,也因此找到了问题的所在。通过查看代码,发现几乎每一个函数内部都有类似的Debug语句,如
 
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %u\n", (unsigned int)pcb>snd_queuelen));
 
其定义在Debug.h中实现:
define LWIP_DEBUGF(debug,x) do { if (((debug) & DBG_ON) && ((debug) & DBG_TYPES_ON) && (((debug) & DBG_MASK_LEVEL) >= DBG_MIN_LEVEL)) { LWIP_PLATFORM_DIAG(x); if ((debug) & DBG_HALT) while(1); } } while(0)
 
#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0)
 
不过我不是很明白为什么使用do{}while(0)。我猜测这种表示方法,是为了将函数内容封装为一句话,从而避免由于宏定义直接插入而可能引起的名字冲突之类的问题。确实令人佩服。。
 
 
采用RawAPI工作方式发送数据,数据量i较小的情况下,不存在问题,发送大数据量时,存在很大的问题:
 
主要原因在于啊,RawAPI工作模式基于回调,对于接受过程而言,通常需要用户主动去循环检测是否有数据包到达,一般是通过调用最底层的设备驱动程序实现此步骤;一旦有数据包到达,则提交给协议栈处理,如果这个数据包是特定链接的数据包,则协议处理完成之后交给用户定义的回调函数处理。对于数据发送过程,通用是用户通过tcp_write,tcp_output来主动发起发送操作。
 
     问题的关键在于,发送一次数据后协议栈会缩小滑动窗口的大小,直到接收到对方的应答,再扩大滑动窗口的大小,但是应答的接收同样是用户主动发起的,一般而言需要在发送结束之后才执行新的接收函数。这样导致的结果就是接收方发送的应答没有被发送方接收到。如果发送少量的数据,不会出现类似问题,发送数量较大时,就会发现最终发送的数据只有滑动窗口的大小。
 
    因此需要将大量数据的发送,划分为小块的数据发送,并且在每次发送之后都要调用底层的数据接收函数接收应答数据。

你可能感兴趣的:(raw,lwip协议,api工作模式)