畢業設計之路(6)——uip

好久沒有來博客了。編程

心情也很差,可是畢業設計仍是要繼續的。數組

跟老師商量改了畢業設計的要求,MCU換了,TCP/IP協議棧也換了,換成STM32與UIP了。換的緣由很蛋疼,以前的那個跟我用的WIN7兼容性不好,不少軟件出問題,因此放棄了。服務器

先從uip看起,版本1.0,貌似好久沒有更新,這是最新的版本了吧。看看uip英文資料開始學習,仍是爲了防止忘記,順便爲畢業論文準備,因此記下一些學習內容。網絡

——————————————————————————————————————————————————分割線,上面是廢話app

下面內容都是參考英文文檔tcp

uip是一個開源的微型協議棧,主要用於8位,16位MCU,佔用內存少,而且代碼少,容易移植。函數

它既能夠用於多任務的操做系統中,如ucos。也能單獨存在,傳說中的裸奔。性能

uip的主循環學習

uip主循環中重複作着兩件事情。測試

  • 查看是否收到數據包
  • 查看週期性超時是否發生
若是有數據包到達,則會在主循環中調用輸入處理函數,uip_input(),這個函數不會發生阻塞,而是馬上返回。它返回時,相應接收這個數據包的應用程序或協議棧會產生一個或多個將要被髮送的迴應數據包。若是是這樣的話,底層的網絡設備驅動會被調用去發送這些數據包。
週期性超時是用於驅動依靠定時器的TCP機制,好比延時確認,重發,估算往返時間。若是主循環中週期性定時發生,uip就會調用定時處理函數uip_periodic().
uip與具體平臺有關的函數
uip有幾個函數是跟具體平臺有關實現有關的。一個是校驗和計算,一個是32位I附加值運算。
校驗和計算
在接收和發送數據包過程,校驗和計算都是很重要的,且每次發送和接收時都要計算校驗和,因此校驗和函數必須頗有效率。這在不少狀況下就意味着校驗和計算必須針對於運行uip的不一樣平臺而作出一些手動調整。
    雖然uip包含了通用的校驗和計算,可是也留了兩個函數來針對特定的平臺,這兩個函數是uip_ipchksum()和uip_tcpchksum(),在這兩個校驗和函數中,可使用匯編語言高度優化來超過C語言的效率。
32位附加值運算
TCP中的32位運算也並非在全部平臺上都有效,因此有一個針對特定平臺的關於32位附加值實現的函數uip_add32().
uip的內存管理
uip不使用動態分配內存。而是用一個單獨的全局緩衝區儲存數據包,還有一個固定的數組來儲存鏈接狀態。這個全局緩衝區足夠大能夠儲存一個包的最大大小。當有個數據包被接收到,設備驅動就會把這個包放在這個全局緩衝區裏而後調用TCP/IP棧。若是這個包包含數據的話,那麼TCP/IP協議棧就會通知相應的應用程序。由於這個在這個緩衝區的數據會被接下來到達的數據覆蓋,因此應用程序不得不當即處理這些數據或者把這些數據放到第二緩衝區以便接下來處理。在應用程序處理這些數據以前這個全局緩衝區不會被新來的數據包覆蓋。在處理當前數據包時新來的數據包必須排隊。許多單片以太網控制器都有足夠大的片內緩衝區來包含至少4個最大大小的以太網幀。若是緩衝區滿了,接下來的數據就會被丟棄。這會致使性能下降,但只是發生在多重鏈接的狀況下。這是由於uip建議一個很是小的接收窗口,這意味着每次鏈接時僅僅只有一個TCP段在網絡中。
在uip中,用於接收數據包的全局緩衝區也用於TCP/IP頭部的傳出數據。若是應用程序發送動態數據,它會使用全局緩衝區的部分來做爲臨時緩衝區。爲了傳送這些數據,應用程序會傳遞一個指針和數據的長度到棧中。TCP/IP的頭部被寫入全局緩衝區,而且一旦產生頭部數據,設備驅動就會發送頭部信息和應用程序數據到網絡中。這個數據不是排隊須要重發的數據。而是應用程序從新產生數據若是須要重發的話。
uip須要的總的內存量是根據特定的運行狀況肯定的。內存的配置肯定了系統處理的流量數和最大鏈接數。

uip的API接口
由於與uip協議棧的緣由,它不使用傳統的BSD套接字API,它有兩種API用於應用編程,一種相似BSD套接字API,還有一種是基於事件的API,這種須要內存比前者更少。
基於事件的API的意思是有一個應用程序運行在uip之上,當處理髮生的特定事件時,由uip調用處理相關事件。這些事件包括接收到或發送包,創建鏈接時,當數據須要重發時等等。
另外uip不一樣於其餘TCP/IP協議棧的地方是須要手動處理重發數據,也就是要本身在應用程序裏編寫代碼處理要重發的數據,其餘協議棧都是自動處理。這樣作的理由也是爲了節約內存。
應用程序事件
處理應用程序事件的函數是UIP_APPCALL(),當發生任何事件時都會調用此函數。每一個事件都有特定的測試函數來區分是哪一種事件,這個函數是一個宏實現,須要注意的是,事件能夠同時發生。
鏈接指示器
當uip調用一個應用程序,全局變量uip_conn被設置成一個指向uip_conn結構體的指針,這個變量被稱做當前鏈接。唉這個結構體中有些變量是有用的,好比用來區分要鏈接的是何種服務或者是鏈接對方的IP地址。一個典型的應用就是經過結構體中的變量uip_conn->lport看鏈接端口來肯定是何種服務,好比若是是80端口,就是HTTP服務器應用程序。
數據接收
若是測試函數uip_newdata()非零,那麼說明接收到新數據。接收到數據的長度能夠經過uip_datalen()函數得到。數據不會被uip緩衝,可是當函數返回時數據會被覆蓋。因此應用程序必須及時處理該數據或者將數據放入另外一個緩衝區中。
發送數據
發送數據時,uip經過接收者的TCP窗口大小和有效的緩衝區空間來調整發送數據的長度。緩衝空間的大小由內存配置決定,所以有可能不是全部發送的數據都會到達接收者一方。因此能夠調用uip_mss()看實際到底有多少數據發送出去了。
發送數據的函數是uip_send(),這個函數須要兩個參數,一個是指向發送數據的指針和發送數據的長度。若是應用程序須要RAM空間來發送數據的話,那麼包緩衝區(就是由uip_appdata指向的緩衝區)能夠用於此目的。
在一個鏈接的同一時間只能有一塊數據被髮送,在一次應用程序裏調用屢次uip_send()是不可能的,它只會把最後調用的數據包發出去。
數據重發
重發是由週期TCP定時器驅動的,每次超時定時器調用時,每一個鏈接的重發定時器就會減小,若是重發定時器減小到0,那麼重發就要重發數據。由於uip在發送數據包後不會保存數據,因此須要手動處理重發數據。當uip肯定有一段須要重發時,應用程序調用uip_rexmit()設置標誌,代表有重發要求。
應用程序會檢查重發標誌而後產生重發數據,從應用程序角度來看,重發的數據和原來的數據沒有什麼不一樣,因此這兩段代碼是同樣的。
關閉鏈接
應用程序經過調用uip_close()來關閉鏈接。這種關閉是正常的關閉鏈接。若是爲了表示是嚴重錯誤而致使的關閉,那麼應用程序應該調用uip_abort()來終止鏈接。
若是鏈接被關閉的話,那麼uip_closed()會返回真,接着應用程序就能夠繼續作必要的清理工做了。
報告錯誤
在一個鏈接中有兩種嚴重的錯誤會發生,一種是鏈接被異常終止或者數據屢次重發無效而終止。uip會分別經過調用測試函數uip_aborted()和uip_timeout()來報告這些錯誤信息。
輪詢
當鏈接空閒時,uip就會在每次超時時間到達時進行輪詢。輪詢的函數是uip_poll()。
輪詢的目的有兩個,第一個目的是讓應用程序知道有空閒的鏈接,並讓空閒過久的鏈接關閉。第二個目的是讓應用程序發送新產生的數據。發送數據只能由uip來調用。所以輪詢是在空閒鏈接時發送數據的惟一方式。
監聽端口
監聽端口的函數是uip_listen()。當鏈接須要和端口綁定時,uip就會建立一個鏈接並調用此函數。若是應用程序調用此函數的話,uip_connected()就會返回真。
開始鏈接
打開一個新的鏈接的函數是uip_connect(),這個函數會返回一個指針指向uip_conn()結構體。若是沒有多餘的空閒槽,那麼函數返回NULL。
函數uip_ipaddr()用於將IP地址放入兩個16位的數組,用來表示IP地址。
相關文章
相關標籤/搜索