uip-學習筆記(移植篇)
UIP
1、 uip_input(); 當網絡卡驅動收到一個包時,將包存放於全域性緩衝區uip_buf中,包的大小由全域性變數uip_len約束;同時將呼叫uip_input();該函式會根據包首部的協議處理這個包將該包傳送給需要該包的應用程式;當該函式返回時,一個輸出包同樣放在全域性緩衝區uip_buf裡;大小賦給uip_len;若uip_len等於0;說明沒有包要傳送。否則呼叫系統底層的發包函式,將該包傳送至網路上。
2、 uip_periodic(); uip週期計時是用於驅動所有的uip內部時鐘事件。當週期計時激發,每一個TCP連線都會呼叫uip_periodic()函式;類似於uip_input()函式;uip_periodic()函式返回時,輸出的IP包要放到uip_buf中;供底層系統查詢uip_len的大小發送。
3、 由於使用TCP\IP的應用場景很多,因此應用程式作為單獨的模組由使用者實現。Uip協議棧提供一系列介面函式供使用者程式呼叫,其中大部分函式有C的巨集命令實現的,主要是為了速度、程式碼大小、效率和堆疊的使用。使用者需要將應用層入口程式作為介面提供給uip協議棧,並將這個函式定義為巨集UIP_APPCALL()。這樣uip在接受到底層傳來的資料包後,在需要送到上層應用程式處理的地方,呼叫UIP_APPCALL()。在不用修改協議棧的情況下可以適配不同的應用程式。
4、 Uip協議棧為我們提供了很多介面函式,這些函式在uip.h中定義,為了減少函式呼叫造成的額外支出,大部分介面函式是以巨集命令實現的,uip提供的介面函式有:
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();
5、 uip的移植
1、 uip1.0原始碼中有以下檔案:apps資料夾 doc資料夾 lib資料夾 uip資料夾 unix資料夾 README.txt檔案 uip-1.0-changelog.txt檔案。其中apps資料夾裡面是uip提供的各種參考程式碼,本實驗,我們主要用到裡面的webserver部分。Doc資料夾裡面是uip的一些說明文件,是學習uip的官方資料。Lib資料夾裡面是用於記憶體管理的一些程式碼,我們這裡沒有用到。Uip裡面就是uip1.0的原始碼了,我們全部笑納。Unix裡面提供的是具體的應用例項,我們移植參考主要是依照這個裡面的程式碼。
2、 移植第一步:實現在unix資料夾下tapdev.c裡面的三個函式。①、首先是tapdev_init()函式,該函式用於初始化網絡卡(也就是我們的ENC28J60),通過這個函式實現網絡卡初始化。②、其次需實現的函式是tapdev_read()函式,該函式用於從網絡卡讀取一包資料,將讀取到的資料存放於全域性快取uip_buf中,資料的長度返回給uip_len;③、最後需實現的是tapdev_send()函式,該函式用於向網絡卡傳送一包資料,將全域性緩衝區uip_buf裡面的資料傳送出去,其實這三個函式就是實現最底層的網絡卡操作。
3、 移植第二步:因為uip協議棧需要使用時鐘,為TCP和ARP的定時器服務,因此我們需要STM32提供一個定時器做時鐘,提供10ms計時(假設clock_arch.h裡面的CLOCK_CONF_SECOND為10),通過colock-arch.c裡面的clock_time()函式返回給uip使用。
4、 移植第三步:配置uip-conf.h裡面的巨集定義選項。主要用於設定TCP最大連線數、TCP監聽埠、CPU大小端模式等,這個大家根據自己需要配置即可。
6、通過以上三步的修改,我們基本上就完成了uip的移植。在使用uip的時候,一般通過如下順序:
1、實現介面函式(回撥函式)UIP_APPCALL。
該函式是我們使用uip最關鍵的部分,它是uip和應用程式的介面,我們必須根據自己的需要,在該函式做各種處理,而做這些處理的觸發條件,就是前面第四點提到的uip提供的那些介面函式,如uip_newdata()、uip_acked()、uip_close()等等。另外,如果是UDP,那麼還需要實現UIP_UDP_APPCALL回撥函式。
2、呼叫tapdev_init()函式,先初始化網絡卡。
此步先初始化網絡卡,配置MAC地址,為uip和網路通訊做好準備。
3、呼叫uip_init()函式,初始化uip協議棧。
此步主要用於uip自身初始化,我們直接呼叫就是。
4、設定IP地址、閘道器以及掩碼
這個和電腦上網差不多,只不過我們這裡是通過uip_ipaddr()、uip_sethostaddr()、uip_setdraddr()、和uip_setnetmask()等函式實現。
5、 設定監聽埠
Uip根據你設定的不同監聽埠,實現不同的服務,比如我們實現webserver就監聽80埠(瀏覽器預設的埠是80埠),凡是發現80埠的資料,都通過webserverd 的APPCALL函式處理。根據自己的需要設定不同的監聽埠。不過uip有本地埠(iport)和遠端埠(rport)之分,如果是做伺服器,我們通過監聽本地客戶端(iport)實現;如果是做客戶端,則需要遠端埠(rport)。
6、 處理uip事件
最後,uip通過uip_polling函式輪訓處理uip事件。該函式必須插入到使用者的主迴圈裡面(也就是必須每隔一定時間呼叫一次)。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1、Clock-arch.c,屬於uip協議棧,uip通過該程式碼裡面的clock_time()函式獲取時鐘節拍。
2、Tapdev.c,同樣是屬於uip提供,用來實現uip與網絡卡的介面,該檔案實現tapdev_init()、3、tapdev_read()、tapdev_send()三個重要函式。
4、tcp_demo.c,完成UIP_APPCALL函式函式的實現,即tcp_demo_appcall()函式。該函式根據埠的不同,分別呼叫不同的appcall函式,實現不同功能。同時該檔案還實現了uip_log函式,用於列印日誌。
5、tcp_client_demo.c,完成一個簡單的TCP客戶端應用,實現與電腦TCP服務端資料收發。
6、tcp_server_demo.c,完成一個簡單的TCP服務端應用,實現與電腦TCP客戶端的資料收發。
7、httpd.c、http-cgi.c、http-fs.c和httpd-strings.h,屬於uip提供的WEB伺服器參考程式碼,我們通過修改部分程式碼,實現一個簡單的web伺服器。