uIP协议栈分析
轉載地址:http://blog.sina.com.cn/s/blog_abd39cc70101fj1f.html
uIP特性
uIP協議棧往掉了完整的TCP/IP中不常用的功能,簡化了通訊流程,但保存了網絡通訊必須使用的協議,設計重點放在了IP/TCP/ICMP/UDP/ARP這些網絡層和傳輸層協議上,保證了其代碼的通用性和結構的穩定性。
由于uIP協議棧專門為嵌進式系統而設計,因此還具有如下優越功能:
(1)????代碼非常少,其協議棧代碼不到6K,很方便閱讀和移植。
(2)????占用的內存數非常少,RAM占用僅幾百字節。
(3)????其硬件處理層、協議棧層和應用層共用一個全局緩存區,不存在數據的拷貝,且發送和接收都是依靠這個緩存區,極大的節省空間和時間。
(4)????支持多個主動連接和被動連接并發。
(5)????其源代碼中提供一套實例程序:web服務器,web客戶端,電子郵件發送程序(SMTP客戶端),Telnet服務器,?DNS主機名解析程序等。通用性強,移植起來基本不用修改就可以通過。
(6)????對數據的處理采用輪循機制,不需要操縱系統的支持。
由于uIP對資源的需求少和移植輕易,大部分的8位微控制器都使用過uIP協議棧,?而且很多的著名的嵌進式產品和項目(如衛星,Cisco路由器,無線傳感器網絡)中都在使用uIP協議棧。
uIP架構
uIP相當于一個代碼庫,通過一系列的函數實現與底層硬件和高層應用程序的通訊,對于整個系統來說它內部的協議組是透明的,從而增加了協議的通用性。uIP協議棧與系統底層和高層應用之間的關系如圖2-1所示。
 ????從上圖可以看出,uIP協議棧主要提供了三個函數供系統底層調用。即uip_init(), uip_input()?和uip_periodic()。其與應用程序的主要接口是UIP_APPCALL( )。
uip_init()是系統初始化時調用的,主要初始化協議棧的偵聽端口和默認所有連接是封閉的。
當網卡驅動收到一個輸進包時,將放進全局緩沖區uip_buf中,包的大小由全局變量uip_len約束。同時將調用uip_input()函數,這個函數將會根據包首部的協議處理這個包和需要時調用應用程序。當uip_input()返回時,一個輸出包同樣放在全局緩沖區uip_buf里,大小賦給uip_len。假如uip_len是0,則說明沒有包要發送。否則調用底層系統的發包函數將包發送到網絡上。
uIP周期計時是用于驅動所有的uIP內部時鐘事件。當周期計時激發,每一個TCP連接都會調用uIP函數uip_periodic()。類似于uip_input()函數。uip_periodic()函數返回時,輸出的IP包要放到uip_buf中,供底層系統查詢uip_len的大小發送。
由于使用TCP/IP的應用場景很多,因此應用程序作為單獨的模塊由用戶實現。uIP協議棧提供一系列接口函數供用戶程序調用,其中大部分函數是作為C的宏命令實現的,主要是為了速度、代碼大小、效率和堆棧的使用。用戶需要將應用層進口程序作為接口提供給uIP協議棧,并將這個函數定義為宏UIP_APPCALL()。這樣,uIP在接受到底層傳來的數據包后,在需要送到上層應用程序處理的地方,調用UIP_APPCALL( )。在不用修改協議棧的情況下可以適配不同的應用程序。
uIP在MCS-51單片機上的移植
1.為此項目建立一個keil C工程,建立src目錄存放源文件。
2.通過閱讀uip-1.0\unix\main.c,了解uIP的的主循環代碼架構,并將main.c放到src目錄下。
3.仿照uip-1.0\unix\tapdev.c寫網卡驅動程序,與具體硬件相關。這一步比較費點時間,不過好在大部分網卡芯片的驅動程序都有代碼鑒戒或移植。驅動需要提供三個函數,以RTL9019AS驅動為例。
etherdev_init():網卡初始化函數,初始化網卡的工作模式。
u16_t etherdev_read(void):讀包函數。將網卡收到的數據放進全局緩存區uip_buf中,返回包的長度,賦給uip_len。
void etherdev_send(void):發包函數。將全局緩存區uip_buf里的數據(長度放在uip_len中)發送出往。
所以,收包和發包主要是操縱uip_buf和uip_len。具體驅動分析可參考《第三章??網絡芯片的驅動》。
4.由于uIP協議棧需要使用時鐘,為TCP和ARP的定時器服務。因此使用單片機的定時器0用作時鐘,每20ms讓計數TIck_cnt加1,這樣,25次計數(0.5S)滿了后可以調用TCP的定時處理程序。10S后可以調用ARP老化程序。對uIP1.0版本,增加了timer.c/timer.h,專門用來治理時鐘,都放到src下。
5.uIP協議棧的主要內容在uip-1.0\uip\下的uip.c/uip.h中,放到src下。假如需要ARP協議,需要將uip_arp.c和uip_arp.h也放到src下。
6.uipopt.h/uip-cONf.h是配置文件,用來設置本地的IP地址、網關地址、MAC地址、全局緩沖區的大小、支持的最大連接數、偵聽數、ARP表大小等。需要放在src下,并且根據需要配置。在V1.00版本中對配置做了如下修改:
(1)配置IP地址,默認先關IP,在初始化中再設定。
#define UIP_FIXEDADDR???0
#define UIP_IPADDR0?????192
#define UIP_IPADDR1?????168
#define UIP_IPADDR2?????1?
#define UIP_IPADDR3?????9
#define UIP_NETMASK0????255
#define UIP_NETMASK1????255
#define UIP_NETMASK2????255
#define UIP_NETMASK3????0??
#define UIP_DRIPADDR0???192
#define UIP_DRIPADDR1???168
#define UIP_DRIPADDR2???1?
#define UIP_DRIPADDR3???1??
(2)使能MAC地址
#define UIP_FIXEDETHADDR 1 ?
#define UIP_ETHADDR0????0x00?
#define UIP_ETHADDR1????0x4f
#define UIP_ETHADDR2????0x49
#define UIP_ETHADDR3????0x12
#define UIP_ETHADDR4????0x12?
#define UIP_ETHADDR5????0x13
(3)使能ping功能
#define UIP_PINGADDRCONF??1
(4)封閉主動請求連接的功能
#define UIP_ACTIVE_OPEN 0
(5)將uip_tcp_appstate_t定位u8_t類型。
(6)由于單片機是大端結構,因此宏定義需要修改
#define UIP_CONF_BYTE_ORDER??????UIP_BIG_ENDIAN
(7)暫時不移植打印信息,先封閉
#define UIP_CONF_LOGGING?????0
(8)定義數據結構類型
typedef unsigned char u8_t;
typedef unsigned int u16_t;
typedef unsigned long u32_t;
7.?假如使用keil C的小模式編譯,需要在大部分的RAM的變量前增加xdata。
8.data為keil C的關鍵詞,代碼中所有出現data的地方(主要是參數、局部變量、結構體成員)改為pucdata或ucdata。
9.解決編譯過程中的錯誤。uIP協議棧為C語言編寫,編譯過程中的題目比較少,并且輕易解決。?
uIP的主控制循環
通過實際的代碼說明uIP協議棧的主控制循環。?
 void main(void)
{
???
???
????timer_set(&periodic_timer, CLOCK_CONF_SECOND / 2);
????timer_set(&arp_timer, CLOCK_CONF_SECOND * 10);
????
????init_Timer();
?
????uip_init();
uip_arp_init();
?
????example1_init();
?
????etherdev_init();
?
????uip_ipaddr(ipaddr, 192,168,1,9);
????uip_sethostaddr(ipaddr);
????uip_ipaddr(ipaddr, 192,168,1,16);
????uip_setdraddr(ipaddr);
????uip_ipaddr(ipaddr, 255,255,255,0);
????uip_setnetmask(ipaddr);
?
????while(1)
????{
?
?
????uip_len = etherdev_read();
?
????if(uip_len > 0)
????{
???
????????if(BUF->type == htons(UIP_ETHTYPE_IP))
????????{
????????????uip_arp_ipin();
????????????uip_input();
?????
????????????if(uip_len > 0)
????????{
????????????????uip_arp_out();
????????????????etherdev_send();
????????????}
????????}
?
????????else if(BUF->type == htons(UIP_ETHTYPE_ARP)) {
?????????uip_arp_arpin();
?????????????if(uip_len > 0)
?????????{
?????????????????etherdev_send();
?????????????}
??????}
????????}
?
????????else if(timer_expired(&periodic_timer))
????????{
????????timer_reset(&periodic_timer);
????????for(i = 0; i < UIP_CONNS; i++)
????????{
???????????uip_periodic(i);
???????????if(uip_len > 0)
??????????{
??????????????uip_arp_out();
??????????????etherdev_send();
????????????????}
??????????}?????????
?????????
??????????if(timer_expired(&arp_timer))
??????????{
?????????????timer_reset(&arp_timer);
?????????????uip_arp_timer();
??????????}
????????}
??}
??return;
}
uIP協議棧提供的主要接口
提供的接口在uip.h中,為了減少函數調用造成的額外支出,大部分接口函數以宏命令實現的。
 ????1.初始化uIP協議棧:uip_init()
 ????2.處理輸進包:uip_input()
 ????3.處理周期計時勢件:uip_periodic()
 ????4.開始監聽端口:uip_listen()
 ????5.連接到遠程主機:uip_connect()
 ????6.接收到連接請求:uip_connected()
 ????7.主動封閉連接:uip_close()
 ????8.連接被封閉:uip_closed()
 ????9.發出往的數據被應答:uip_acked()
 ????10.在當前連接發送數據:uip_send()
 ????11.在當前連接上收到新的數據:uip_newdata()
 ????12.告訴對方要停止連接:uip_stop()
 ????13.連接被意外終止:uip_aborted()
總結
 
                            
                        - 上一篇: cadence SPB17.4 - 更换
- 下一篇: 2015年12月7号工作日志------
