使用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來主動發起發送操作。
 
     問題的關鍵在於,發送一次數據後協議棧會縮小滑動窗口的大小,直到接收到對方的應答,再擴大滑動窗口的大小,但是應答的接收同樣是用戶主動發起的,一般而言需要在發送結束之後才執行新的接收函數。這樣導致的結果就是接收方發送的應答沒有被髮送方接收到。如果發送少量的數據,不會出現類似問題,發送數量較大時,就會發現最終發送的數據只有滑動窗口的大小。
 
    因此需要將大量數據的發送,劃分爲小塊的數據發送,並且在每次發送之後都要調用底層的數據接收函數接收應答數據。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章