LwIP及其網(wǎng)絡(luò)編程應(yīng)用實(shí)例_第1頁
LwIP及其網(wǎng)絡(luò)編程應(yīng)用實(shí)例_第2頁
LwIP及其網(wǎng)絡(luò)編程應(yīng)用實(shí)例_第3頁
LwIP及其網(wǎng)絡(luò)編程應(yīng)用實(shí)例_第4頁
LwIP及其網(wǎng)絡(luò)編程應(yīng)用實(shí)例_第5頁
已閱讀5頁,還剩101頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

第九章LwIP及其網(wǎng)絡(luò)編程應(yīng)用實(shí)例1整理pptLwIP介紹LwIP(LightWeightInternetProtocol)是瑞典計(jì)算機(jī)科學(xué)院(SwedishInstituteofComputerScience)的AdamDunkels等人開發(fā)的一套用于嵌入式系統(tǒng)的開源TCP/IP協(xié)議棧。LwIP的含義是輕型IP協(xié)議,其實(shí)現(xiàn)的重點(diǎn)是在保持TCP協(xié)議主要功能的根底上減少對RAM的占用,這使得LwIP協(xié)議棧非常適合在小型嵌入式系統(tǒng)中使用。2整理pptLwIP介紹LwIP的版本較多,較新的版本通常完善或增加了LwIP的功能。LwIP有如下特點(diǎn):IP:支持多網(wǎng)絡(luò)接口下的IP轉(zhuǎn)發(fā)ARP:支持ARP協(xié)議ICMP:支持ICMP協(xié)議UDP:支持UDP協(xié)議TCP:支持TCP協(xié)議,包括擁塞控制、RTT估算和快速恢復(fù)/快速重傳RawAPI:提供專門的內(nèi)部回調(diào)函數(shù),以提高應(yīng)用性能SocketAPI:可選的Berkeley-likesocketAPILwIP的較新版本還提供對以下功能或協(xié)議的支持:IPfragment:IP分片DNS:域名解析SNMP:簡單網(wǎng)絡(luò)管理協(xié)議DHCP:動態(tài)主機(jī)配置協(xié)議PPP:點(diǎn)對點(diǎn)協(xié)議IPv63整理pptLwIP源碼的文件組織LwIP文件目錄的組織結(jié)構(gòu)如下圖,其源代碼全部位于目錄src下。src目錄下一般有5個子目錄LwIP提供的api子目錄、core子目錄、include子目錄和netif子目錄需用戶自己創(chuàng)立的arch目錄。4整理pptLwIP源碼的文件組織每個子目錄包含的某一類相關(guān)的文件,簡要說明如下:api目錄應(yīng)用程序接口文件。arch目錄與硬件和OS有關(guān)的文件,包括網(wǎng)絡(luò)驅(qū)動、移植需要修改的文件。core目錄LwIP的核心代碼,包括ICMP、IP、UDP、TCP等協(xié)議的實(shí)現(xiàn)等。include目錄LwIP的包含文件。netif目錄ARP協(xié)議和LwIP網(wǎng)絡(luò)設(shè)備驅(qū)動程序的模板,提供了網(wǎng)絡(luò)接口驅(qū)動程序的根本框架。5整理pptLwIP的軟件體系結(jié)構(gòu)LwIP的協(xié)議層次:LwIP也是以4層TCP/IP模型為參照來實(shí)現(xiàn)TCP/IP協(xié)議族的。每一個協(xié)議作為一個模塊被實(shí)現(xiàn),同時(shí)還提供了幾個函數(shù)作為協(xié)議的入口點(diǎn)。LwIP并沒有嚴(yán)格地按照分層的方式實(shí)現(xiàn)協(xié)議族。實(shí)際上LwIP使用的是一種比較松散的通訊機(jī)制,通過共享內(nèi)存的方式實(shí)現(xiàn)應(yīng)用層與底層協(xié)議族之間的通訊。LwIP擁有獨(dú)特的緩沖機(jī)制,使得各層次可以更加有效的重復(fù)使用緩沖區(qū)。LwIP盡量防止內(nèi)存復(fù)制,防止了內(nèi)存復(fù)制產(chǎn)生的性能損失。6整理pptLwIP的軟件體系結(jié)構(gòu)與LwIP的協(xié)議層次相匹配,LwIP采用模塊化設(shè)計(jì)的方法實(shí)現(xiàn)。TCP/IP協(xié)議的實(shí)現(xiàn)模塊如ARP、IP、ICMP、UDP、TCP等許多相關(guān)支持模塊。這些支持模塊包括操作系統(tǒng)模擬層、緩沖與內(nèi)存管理子系統(tǒng)、網(wǎng)絡(luò)接口函數(shù)等。7整理pptLwIP的進(jìn)程模型TCP/IP協(xié)議族的進(jìn)程模型指的是采用何種方法把系統(tǒng)分成不同的進(jìn)程。常見的進(jìn)程模型有兩種:每一個協(xié)議作為一個獨(dú)立的進(jìn)程協(xié)議棧作為一個內(nèi)核只占據(jù)一個進(jìn)程。第一種模型必須符合協(xié)議的每一層,協(xié)議層之間通過指定的方式進(jìn)行通訊。優(yōu)點(diǎn)較明顯,即每一種協(xié)議都可以獨(dú)立參與到系統(tǒng)運(yùn)行中,其實(shí)現(xiàn)的代碼也比較簡單,整個協(xié)議棧的層次脈絡(luò)清晰,便于理解和調(diào)試。缺點(diǎn)也是顯而易見的,即數(shù)據(jù)跨層傳遞時(shí)不得不產(chǎn)生進(jìn)程切換以及內(nèi)存復(fù)制。這一缺點(diǎn)極大影響了系統(tǒng)的整體性能,尤其對于嵌入式系統(tǒng)來說更是不能忍受的。第二種模型將協(xié)議棧駐留在操作系統(tǒng)內(nèi)核中,應(yīng)用程序通過系統(tǒng)調(diào)用與協(xié)議棧進(jìn)行通訊。這種設(shè)計(jì)可以使用交叉協(xié)議分層技術(shù),各層協(xié)議不必嚴(yán)格劃分。這種進(jìn)程模型的缺點(diǎn)是層次不清,給理解增加了難度。8整理pptLwIP的進(jìn)程模型LwIP那么采用一種比較靈活的設(shè)計(jì)方法。它可以將所有的協(xié)議駐留在一個進(jìn)程,以便獨(dú)立于操作系統(tǒng)內(nèi)核之外。應(yīng)用程序既可以駐留在LwIP的進(jìn)程中,也可以使用一個單獨(dú)的進(jìn)程。它也可以根據(jù)協(xié)議層次結(jié)構(gòu)創(chuàng)立多個進(jìn)程,但各個進(jìn)程之間只傳送盡可能少的必要信息,而沒有引入額外的內(nèi)存復(fù)制LwIP在協(xié)議層之間切換時(shí),一般只傳遞數(shù)據(jù)緩沖區(qū)的地址,讓需要處理數(shù)據(jù)的協(xié)議層自己去提取。9整理pptLwIP的函數(shù)調(diào)用關(guān)系為了盡量防止不必要的內(nèi)存復(fù)制,LwIP更多的是采用一種基于回調(diào)函數(shù)的設(shè)計(jì)方法。當(dāng)數(shù)據(jù)需要處理或跨層傳遞時(shí),通常是通過調(diào)用事先已定義好的回調(diào)函數(shù)來完成有關(guān)操作。優(yōu)點(diǎn)是大大提高了LwIP的整體性能;缺點(diǎn)是使得LwIP的整個軟件體系顯得略微復(fù)雜,尤其是函數(shù)之間的調(diào)用關(guān)系更為繁瑣。為了理清LwIP的函數(shù)調(diào)用關(guān)系,從兩個不同的方向?qū)@一問題進(jìn)行分析:從不同的協(xié)議層出發(fā),橫向分析各個層次內(nèi)的調(diào)用關(guān)系;從幾種典型的協(xié)議模塊出發(fā),縱向分析各模塊的跨層調(diào)用關(guān)系。10整理ppt整體調(diào)用關(guān)系圖給出了LwIP的整體調(diào)用關(guān)系,根本上涵蓋了LwIP的主要功能模塊和絕大局部的函數(shù)調(diào)用。圖中只標(biāo)注了對LwIP的整個軟件體系起著重要支撐作用的主干函數(shù)11整理ppt協(xié)議層內(nèi)的調(diào)用TCP/IP協(xié)議棧是按功能層組織的,每一層都為上一層提供效勞,并使用下一層提供的效勞。在4層TCP/IP模型中,從下至上依次是網(wǎng)絡(luò)接口層、網(wǎng)際層、運(yùn)輸層和應(yīng)用層?!?〕網(wǎng)絡(luò)接口層網(wǎng)絡(luò)接口層是較高協(xié)議與局域網(wǎng)接口的地方。當(dāng)主機(jī)通過查詢或者中斷方式得知網(wǎng)絡(luò)芯片接收到數(shù)據(jù)幀時(shí),LwIP協(xié)議棧對該數(shù)據(jù)幀進(jìn)行解碼,并判斷數(shù)據(jù)幀的協(xié)議類型:如果是IP協(xié)議,那么將該幀傳遞給上層〔網(wǎng)際層〕的ip_input()函數(shù)進(jìn)行處理;如果是ARP協(xié)議,那么直接傳給本層的arp_input()函數(shù),該函數(shù)根據(jù)需要決定是否調(diào)用arp_replay()進(jìn)行ARP應(yīng)答。當(dāng)上層有數(shù)據(jù)需要通過網(wǎng)絡(luò)接口層進(jìn)行發(fā)送時(shí),當(dāng)前網(wǎng)絡(luò)接口的輸出函數(shù)netif->output()將會被調(diào)用,以完成真正的數(shù)據(jù)發(fā)送過程。12整理ppt協(xié)議層內(nèi)的調(diào)用13整理ppt協(xié)議層內(nèi)的調(diào)用〔2〕網(wǎng)際層網(wǎng)際層負(fù)責(zé)網(wǎng)間尋址〔IP地址〕、數(shù)據(jù)封裝、路由選擇、錯誤處理和診斷等典型協(xié)議有IP協(xié)議和ICMP協(xié)議。當(dāng)從下層〔網(wǎng)絡(luò)接口層〕接收到IP數(shù)據(jù)報(bào)時(shí),調(diào)用ip_input()函數(shù)進(jìn)行處理。根據(jù)IP數(shù)據(jù)報(bào)的協(xié)議字段,LwIP決定將該數(shù)據(jù)報(bào)傳給上層〔運(yùn)輸層〕還是傳給本層。如果IP凈荷中承載的是ICMP協(xié)議,那么本層的icmp_input()函數(shù)將會調(diào)用。當(dāng)不管是上層還是本層有數(shù)據(jù)需要從網(wǎng)際層發(fā)送出去時(shí)LwIP將會調(diào)用ip_output()發(fā)送數(shù)據(jù),或者先調(diào)用ip_route()找到一個適宜的網(wǎng)絡(luò)接口再調(diào)用ip_output_if()發(fā)送數(shù)據(jù)。實(shí)際上ip_output()也是通過先調(diào)用ip_route()再調(diào)用ip_output_if()來實(shí)現(xiàn)的14整理ppt協(xié)議層內(nèi)的調(diào)用15整理ppt協(xié)議層內(nèi)的調(diào)用〔3〕運(yùn)輸層運(yùn)輸層負(fù)責(zé)在網(wǎng)際設(shè)備之間運(yùn)輸數(shù)據(jù),以可靠或不可靠的方式進(jìn)行。TCP和UDP。當(dāng)下層〔網(wǎng)際層〕有數(shù)據(jù)傳給運(yùn)輸層時(shí)LwIP會根據(jù)數(shù)據(jù)類型的不同〔是TCP還是UDP〕調(diào)用該層的tcp_input()或者udp_input()。經(jīng)過一定處理后,LwIP將數(shù)據(jù)由tcp_receive()或udp_input()提交給上層〔應(yīng)用層〕,一般會調(diào)用事先注冊的接收函數(shù)。當(dāng)上層需要發(fā)送數(shù)據(jù)時(shí)LwIP選擇調(diào)用tcp_write()或者udp_send()對數(shù)據(jù)進(jìn)行處理最后通過tcp_output()或udp_send()將數(shù)據(jù)交給下層。16整理ppt協(xié)議層內(nèi)的調(diào)用17整理ppt協(xié)議層內(nèi)的調(diào)用〔4〕應(yīng)用層用戶的應(yīng)用運(yùn)行在應(yīng)用層,該層使用戶可以根據(jù)自己的需要對數(shù)據(jù)進(jìn)行處理。用戶需要發(fā)送數(shù)據(jù)時(shí)由LwIP根據(jù)數(shù)據(jù)類型〔TCP或UDP〕調(diào)用下層〔運(yùn)輸層〕對應(yīng)的發(fā)送函數(shù)。應(yīng)用層并不需要直接關(guān)注數(shù)據(jù)是怎樣發(fā)送出去的。用戶接收的數(shù)據(jù)一般由LwIP調(diào)用下層的接收函數(shù)送達(dá),此后用戶可以根據(jù)實(shí)際情況實(shí)現(xiàn)應(yīng)用程序。18整理ppt典型模塊的跨層調(diào)用對于某一個協(xié)議來說它一般只隸屬于某一個層次〔ARP除外〕。但往往會有其它層次調(diào)用該協(xié)議的有關(guān)函數(shù)而該協(xié)議一般也會主動調(diào)用其它層次的有關(guān)函數(shù)。

〔1〕IP模塊LwIP的較早期版本實(shí)現(xiàn)了IP層大局部的根本功能,能夠發(fā)送、接收以及轉(zhuǎn)發(fā)信息包。接收信息包由網(wǎng)絡(luò)設(shè)備驅(qū)動調(diào)用ip_input()函數(shù)開始處理。完成對IP版本字段及包頭長度的初始完整性檢查同時(shí)還要計(jì)算和驗(yàn)證包頭校驗(yàn)和函數(shù)檢查目的地址是否與網(wǎng)絡(luò)接口的IP地址相符以確定信息包是否到達(dá)預(yù)定主機(jī)。如果一個到達(dá)的信息包被發(fā)現(xiàn)已經(jīng)到達(dá)了目的主機(jī),那么由協(xié)議字段來決定信息包應(yīng)該傳送到哪一個上層協(xié)議。19整理ppt典型模塊的跨層調(diào)用外發(fā)的信息包由ip_output()函數(shù)處理,該函數(shù)使用ip_route()函數(shù)查找適當(dāng)?shù)木W(wǎng)絡(luò)接口來傳送信息包。當(dāng)外發(fā)的網(wǎng)絡(luò)接口確定后,信息包傳給以外發(fā)網(wǎng)絡(luò)接口為參數(shù)的ip_output_if()函數(shù)。所有的IP包頭字段被填充,并且計(jì)算IP包頭校驗(yàn)和。IP信息包的源及目標(biāo)地址作為參數(shù)被傳遞給ip_output_if()函數(shù)。傳輸層協(xié)議UDP與TCP在計(jì)算傳輸層校驗(yàn)和的時(shí)候需要擁有目標(biāo)IP地址,因此一些傳輸層函數(shù)可能會直接直接調(diào)用ip_route()函數(shù)確定接口。這樣這些函數(shù)在外發(fā)數(shù)據(jù)前就沒有必要再對網(wǎng)絡(luò)接口鏈表進(jìn)行檢索,而是直接調(diào)用ip_output_if()函數(shù)外發(fā)數(shù)據(jù)。20整理ppt典型模塊的跨層調(diào)用如果沒有網(wǎng)絡(luò)接口的地址與到達(dá)的信息包的目標(biāo)地址相同,信息包應(yīng)該被轉(zhuǎn)發(fā)。由ip_forward()函數(shù)完成。TTL字段值被減少,當(dāng)減為0的時(shí)候,將會給IP信息包的最初發(fā)送者發(fā)送ICMP錯誤信息,并拋棄該信息包。因?yàn)镮P包頭被改變,因此需要調(diào)整IP包頭校驗(yàn)和。最后,信息包被轉(zhuǎn)發(fā)到適當(dāng)?shù)木W(wǎng)絡(luò)接口。21整理ppt典型模塊的跨層調(diào)用〔2〕ICMP模塊ICMP信息包由ip_input()函數(shù)收到后,轉(zhuǎn)交給icmp_input()函數(shù)對ICMP包頭解碼,然后進(jìn)行適當(dāng)?shù)膭幼鳌H绻枰獙厮驼埱筮M(jìn)行應(yīng)答,那么調(diào)用ip_output()函數(shù)發(fā)送應(yīng)答報(bào)文。某些ICMP消息被傳遞給上層協(xié)議,由傳輸層的特定函數(shù)處理。ICMP目標(biāo)不可到達(dá)消息可以由傳輸層發(fā)送,特別是UDP如udp_input()就可以調(diào)用icmp_dest_unreach()函數(shù)完成這項(xiàng)工作。icmp_dest_unreach()最后也會調(diào)用ip_output()發(fā)送ICMP報(bào)文。22整理ppt典型模塊的跨層調(diào)用23整理ppt典型模塊的跨層調(diào)用〔3〕UDP模塊當(dāng)一個UDP數(shù)據(jù)包到達(dá)時(shí)IP層調(diào)用udp_input()函數(shù)將數(shù)據(jù)包移交給udp_input()。如果需要的話,LwIP會在這里對UDP校驗(yàn)和進(jìn)行檢查。為了找到匹配的UDPPCB,LwIP會對UDPPCB全局鏈表進(jìn)行線性搜索。如果當(dāng)前鏈表中存在匹配的UDPPCB,那么其recv函數(shù)會被調(diào)用。發(fā)送數(shù)據(jù)的過程由應(yīng)用程序調(diào)用udp_send()函數(shù)發(fā)起。為了計(jì)算校驗(yàn)和,該函數(shù)會調(diào)用ip_route()確定網(wǎng)絡(luò)接口,因?yàn)樵摻涌诘刂穼⒃谛r?yàn)和的計(jì)算過程中用到。最后,信息包被移交給ip_output_if()函數(shù)傳送。24整理ppt典型模塊的跨層調(diào)用25整理ppt典型模塊的跨層調(diào)用〔4〕TCP模塊TCP處理比UDP處理要復(fù)雜得多與TCP輸入相關(guān)的函數(shù)tcp_input()tcp_process()tcp_receive()與TCP輸出有關(guān)的函數(shù)tcp_write()tcp_enqueue()tcp_output()26整理ppt典型模塊的跨層調(diào)用27整理ppt典型模塊的跨層調(diào)用TCP數(shù)據(jù)的發(fā)送過程一般是由應(yīng)用層發(fā)起。應(yīng)用層調(diào)用tcp_write(),而tcp_write()再調(diào)用tcp_enqueue()。tcp_enqueue()函數(shù)會在必要時(shí)將數(shù)據(jù)分割成適當(dāng)大小的TCP段,然后把這些TCP段放到所屬連接的傳輸隊(duì)列中。這時(shí)tcp_output()函數(shù)會判斷接收器窗口是否擁有足夠大的空間,阻塞窗口是否也足夠大,如果條件滿足,就調(diào)用ip_route()找到一個適宜的接口,再調(diào)用ip_output_if()完成發(fā)送過程。即使當(dāng)時(shí)不能發(fā)送也不要緊,這是因?yàn)長wIP設(shè)置了定時(shí)器函數(shù)tcp_tmr(),該函數(shù)每隔固定時(shí)間就會被調(diào)用一次。tcp_tmr()會對當(dāng)前連接的傳輸隊(duì)列進(jìn)行分析,并根據(jù)需要調(diào)用tcp_output()執(zhí)行數(shù)據(jù)發(fā)送操作。28整理ppt典型模塊的跨層調(diào)用TCP數(shù)據(jù)的接收過程由網(wǎng)絡(luò)接口層發(fā)起。網(wǎng)絡(luò)接口層將數(shù)據(jù)包傳遞給ip_input()函數(shù),該函數(shù)驗(yàn)證IP頭后移交TCP段給tcp_input()函數(shù)。tcp_input()函數(shù)主要完成兩項(xiàng)工作初始完整性檢查〔也就是校驗(yàn)和驗(yàn)證與TCP選項(xiàng)解析判定這個TCP段屬于哪個TCP連接。接著,這個TCP段到達(dá)tcp_process()函數(shù)。tcp_process()函數(shù)實(shí)現(xiàn)了TCP狀態(tài)機(jī),任何必要的狀態(tài)轉(zhuǎn)換都在這里實(shí)現(xiàn)。當(dāng)該TCP所屬的連接正處于接受網(wǎng)絡(luò)數(shù)據(jù)的狀態(tài)時(shí),tcp_receive()函數(shù)將被調(diào)用。最后,tcp_receive()函數(shù)將數(shù)據(jù)傳給上層的應(yīng)用程序,完成接收過程。如果收到一個ACK應(yīng)答確認(rèn)數(shù)據(jù),說明接收器同意接收更多的數(shù)據(jù),此時(shí)tcp_output()函數(shù)將會被調(diào)用。29整理pptLwIP的內(nèi)存管理LwIP的包緩沖區(qū)pbufpbuf是LwIP信息包的內(nèi)部表示。pbuf結(jié)構(gòu)既支持動態(tài)內(nèi)存分配以保存信息包內(nèi)容,又支持讓信息包數(shù)據(jù)駐留在靜態(tài)存儲區(qū)。多個pbuf可以通過一個鏈表結(jié)構(gòu)鏈接成一個pbuf鏈,從而使一個信息包穿越多個pbuf。pbuf的內(nèi)部結(jié)構(gòu)定義為structpbuf{structpbuf*next; //指向下一個pbufvoid*payload; //指向?qū)嶋H的數(shù)據(jù)負(fù)載u16_ttot_len; //pbuf鏈的數(shù)據(jù)負(fù)載總長度u16_tlen; //該pbuf的數(shù)據(jù)負(fù)載長度u16_tflags; //pbuf的類型標(biāo)志u16_tref; //pbuf被引用的次數(shù)};30整理pptLwIP的內(nèi)存管理pbuf結(jié)構(gòu)包括兩個指針,兩個長度字段,一個標(biāo)志字段和一個引用計(jì)數(shù)字段。next指針指向pbuf鏈中下一個pbuf的位置;payload指針指向pbuf中數(shù)據(jù)負(fù)載的開始位置len字段包含pbuf中數(shù)據(jù)內(nèi)容的長度;tot_len字段包含當(dāng)前pbuf的長度與在這個pbuf鏈中隨后的所有pbuf的len字段之和flags字段標(biāo)識pbuf的類型;ref字段指出pbuf被引用的次數(shù)。pbuf有四種類型PBUF_RAMPBUF_ROMPBUF_REFPBUF_POOL31整理pptPBUF_RAM類型的pbufPBUF_RAM在事先劃分好的內(nèi)存堆棧中分配,用于存放應(yīng)用程序動態(tài)產(chǎn)生的數(shù)據(jù)。圖示的是一個PBUF_RAM類型的pbuf實(shí)例,其實(shí)際的數(shù)據(jù)負(fù)載存放在由協(xié)議棧管理的存儲區(qū)中。既然PBUF_RAM類型的pbuf用于應(yīng)用程序發(fā)送的數(shù)據(jù)被動態(tài)生成的情況,那么在這種情況下pbuf系統(tǒng)不僅為應(yīng)用數(shù)據(jù)分配內(nèi)存,還應(yīng)給為這些數(shù)據(jù)預(yù)置的包頭分配內(nèi)存。pbuf系統(tǒng)不可能預(yù)先知道為這些數(shù)據(jù)預(yù)置什么樣的包頭,因而考慮最壞的情況。32整理pptPBUF_ROM/PBUF_REF類型的pbufPBUF_ROM類型的pbuf的payload指針指向不由協(xié)議棧管理的外部存儲區(qū)如應(yīng)用程序管理的存儲器為用戶數(shù)據(jù)分配的緩存。由于由應(yīng)用程序交付的數(shù)據(jù)不能被改動因此就需要動態(tài)地分配一個PBUF_RAM來裝載協(xié)議的首部然后將PBUF_RAM(首部)添加到PBUF_ROM(數(shù)據(jù))的前面。這樣就構(gòu)成了一個完整的數(shù)據(jù)分組〔pbuf鏈〕33整理pptPBUF_ROM/PBUF_REF類型的pbuf34整理pptPBUF_ROM/PBUF_REF類型的pbuf圖中的PBUF_ROM還可以是PBUF_REF,二者的特性非常相似,都可以實(shí)現(xiàn)數(shù)據(jù)的零拷貝,但是當(dāng)發(fā)送數(shù)據(jù)需要排隊(duì)時(shí)就表現(xiàn)出PBUF_REF的特性了。例如待發(fā)送的分組需要在ARP隊(duì)列中排隊(duì),假設(shè)這些分組中有PBUF_ROM類型的pbuf,那么直到分組被處理之前,被引用的應(yīng)用程序的這塊存儲區(qū)域都不能另作它用。但如果是PBUF_REF類型的pbuf,LwIP那么會在數(shù)據(jù)分組排隊(duì)時(shí)為PBUF_REF類型的pbuf分配緩存(PBUF_POOL或PBUF_RAM),并將引用的應(yīng)用程序的數(shù)據(jù)拷貝到分配的緩存中。這樣應(yīng)用程序中被引用數(shù)據(jù)的存儲區(qū)域就能被釋放。35整理pptPBUF_POOL類型的pbufPBUF_POOL是具有固定容量的pbuf,其容量大小通過宏定義來指定。在協(xié)議棧管理的內(nèi)存中初始化了一個pbuf池,具有相同尺寸的pbuf都是從這個pbuf池中分配得到。一般使用多個PBUF_POOL鏈接成一個鏈表,用于存儲數(shù)據(jù)分組36整理pptPBUF_POOL類型的pbuf37整理pptPBUF_POOL類型的pbufPBU_POOL主要用于網(wǎng)絡(luò)設(shè)備驅(qū)動層由于分配一個pbuf的操作可以快速完成,所以PBUF_POOL非常適合用于中斷處理。一般來說,收到的pbuf是PBUF_POOL類型,發(fā)送出的pbuf是PBUF_ROM或PBUF_RAM類型。不同類型的pbuf擁有各自的特點(diǎn)和不同的使用目的,因此只有正確選用,才能最好地發(fā)揮LwIP的特性。38整理pptLwIP的內(nèi)存管理LwIP的內(nèi)存區(qū)域主要用于裝載待接收和發(fā)送的網(wǎng)絡(luò)數(shù)據(jù)分組。當(dāng)接收到分組或者有分組要發(fā)送時(shí),LwIP協(xié)議棧為這些分組分配緩存;在接收到的分組交付給應(yīng)用程序或者分組己經(jīng)發(fā)送完畢后,LwIP協(xié)議棧對分配的緩存進(jìn)行回收利用。協(xié)議棧分配的緩存必須能容納各種大小的報(bào)文例如從僅僅幾個字節(jié)的ICMP應(yīng)答報(bào)文到幾百個字節(jié)的TCP分段報(bào)文。39整理pptPBUF_RAM的內(nèi)存管理LwIP協(xié)議棧首先從系統(tǒng)內(nèi)存中開辟一塊連續(xù)的靜態(tài)存儲區(qū)域該區(qū)域的大小可以事先通過宏定義指定。協(xié)議棧將該區(qū)域作為PBUF_RAM的專用區(qū)域所有與PBUF_RAM有關(guān)的內(nèi)存操作都被限制在該區(qū)域內(nèi),從而確保了協(xié)議棧不會因非法訪問系統(tǒng)內(nèi)存的其它區(qū)域而擾亂其它程序的正常運(yùn)行。40整理pptPBUF_RAM的內(nèi)存管理為了方便內(nèi)存管理,協(xié)議棧定義了一個比較小的結(jié)構(gòu)體mem,并將該結(jié)構(gòu)體置于內(nèi)存分配塊的頂部來保存內(nèi)存分配記錄。該結(jié)構(gòu)體擁有三個成員變量,分別為兩個“指針〞和一個標(biāo)志,其中next與prev分別指向內(nèi)存的下一個和上一個分配塊,used標(biāo)志標(biāo)示該內(nèi)存塊是否已被分配。next和prev并不是真正的指針,它們本質(zhì)上是數(shù)組的下標(biāo),并沒有直接指向真正的地址。41整理pptPBUF_RAM的內(nèi)存管理〔1〕初始化使用PBUF_RAM內(nèi)存之前,需對PBUF_RAM的專用內(nèi)存區(qū)域進(jìn)行初始化工作,即對該區(qū)域進(jìn)行一定的格式設(shè)置。LwIP協(xié)議棧在該區(qū)域的頭部和尾部各設(shè)置了一個mem結(jié)構(gòu)以協(xié)助管理內(nèi)存,如下圖。在頭部的mem結(jié)構(gòu)中,next指向尾部mem,prev指向該區(qū)域的起始處,used(=0)說明該mem結(jié)構(gòu)后面的區(qū)域尚未使用;在尾部的mem結(jié)構(gòu)中,next和prev均指向該mem自身,used(=1)說明該mem結(jié)構(gòu)后面無可用的內(nèi)存。在該區(qū)域的末尾處,協(xié)議棧預(yù)留了對齊空間,其主要目的是防止操作過程中因?qū)R而導(dǎo)致的對該專用區(qū)域之外的存儲空間的越界訪問。42整理pptPBUF_RAM的內(nèi)存管理43整理pptPBUF_RAM的內(nèi)存管理〔2〕分配PBUF_RAM內(nèi)存塊分配內(nèi)存時(shí)首先根據(jù)所申請分配的大小來搜索所有未被使用的內(nèi)存分配塊搜索到的最先滿足條件的內(nèi)存塊將分配給申請者。第一次分配時(shí)只要申請分配的大小沒有超出限制,便會在PBUF_RAM專用存儲區(qū)域的開頭分配所需要的內(nèi)存44整理pptPBUF_RAM的內(nèi)存管理經(jīng)過屢次的內(nèi)存分配和釋放操作后,PBUF_RAM存儲區(qū)中會存在多個大小不一的未使用塊。此時(shí)如果需要分配一個新的內(nèi)存塊,有可能搜索到的第一個空閑內(nèi)存塊空間不夠。在這種情況下,內(nèi)存管理機(jī)制會繼續(xù)往后搜索未使用塊,直到搜索到足夠大的空閑內(nèi)存塊或搜索到存儲區(qū)的末尾。45整理pptPBUF_RAM的內(nèi)存管理〔3〕釋放PBUF_RAM內(nèi)存塊對不再利用的內(nèi)存塊,需要進(jìn)行回收,以便下次需要分配內(nèi)存塊時(shí)重新使用?;厥諆?nèi)存塊時(shí),管理該內(nèi)存塊的mem結(jié)構(gòu)的used標(biāo)志將被清零,以說明該內(nèi)存塊已不再被使用,可以重新對其進(jìn)行分配46整理pptPBUF_RAM的內(nèi)存管理為了防止內(nèi)存碎片的產(chǎn)生,每回收一個內(nèi)存塊后,其上一個與下一個分配塊的used標(biāo)志將會被檢查:如果它們中的任何一個還未被使用〔used=0〕,那么這個內(nèi)存塊將被合并到一個更大的未使用內(nèi)存塊中。只有經(jīng)過了以上操作后,釋放內(nèi)存的工作才算是已經(jīng)完成。47整理pptPBUF_RAM的內(nèi)存管理合并相鄰空閑塊的一個例如。48整理pptPBUF_RAM的內(nèi)存管理〔4〕調(diào)整PBUF_RAM內(nèi)存塊大小在內(nèi)存的使用過程中,有時(shí)希望調(diào)整已分配的內(nèi)存塊的大小。根據(jù)調(diào)整的方向〔減小/增大〕不同,處理的機(jī)制也不一樣。調(diào)整前先對騰出的內(nèi)存塊大小進(jìn)行預(yù)算:如果該值小于mem結(jié)構(gòu)的長度加內(nèi)存塊的最小長度〔即無法另行分配一個最小長度的內(nèi)存塊〕,那么調(diào)整不被執(zhí)行。調(diào)整時(shí)將在騰出的內(nèi)存塊開頭置以一個新的mem結(jié)構(gòu)以對其進(jìn)行管理,該mem結(jié)構(gòu)的used標(biāo)志為0,表示可以對其進(jìn)行分配使用。同釋放內(nèi)存時(shí)一樣,與新的內(nèi)存塊相鄰的內(nèi)存塊的used標(biāo)志同樣會被檢查,以防止碎片產(chǎn)生。49整理pptPBUF_RAM的內(nèi)存管理給出了減小既定內(nèi)存塊大小的示意圖。50整理pptPBUF_RAM的內(nèi)存管理增大既定內(nèi)存塊的大小時(shí)所采取的機(jī)制與上述操作大為不同。如果希望將某內(nèi)存塊的大小調(diào)整為newsize,那么處理過程是先分配一塊大小為newsize的空閑內(nèi)存塊,然后將原內(nèi)存塊的內(nèi)容復(fù)制到新內(nèi)存塊中,最后再釋放原內(nèi)存塊。51整理pptPBUF_ROM/PBUR_REF的內(nèi)存管理對于PBUF_ROM/PBUF_REF,LwIP協(xié)議棧同樣為其開辟了一塊連續(xù)的存儲區(qū)域。協(xié)議棧定義了結(jié)構(gòu)體memp以協(xié)助PBUF_ROM/PBUF_RAM的內(nèi)存管理。該結(jié)構(gòu)體只有一個成員next,為指向下一個相同結(jié)構(gòu)的存儲區(qū)的指針。PBUF_ROM/PBUF_REF類型存儲區(qū)域初始化后的結(jié)構(gòu)示意圖,多個pbuf在內(nèi)存中以鏈表的形式存在。該種類型pbuf的操作方法可以參考鏈表的一般操作方法。52整理pptPBUF_POOL的內(nèi)存管理PBUF_POOL類型的pbuf同樣擁有自己專用的存儲區(qū)域,該區(qū)域通過預(yù)先從系統(tǒng)內(nèi)存中分配而得。區(qū)域大小由PBUF_POOL類型的pbuf個數(shù)和每個pbuf的緩沖區(qū)大小等參數(shù)共同決定,這些參數(shù)都可以事先通過宏定義指定。對PBUF_POOL類型的內(nèi)存管理,LwIP協(xié)議棧并沒有額外引入類似PBUF_RAM的mem結(jié)構(gòu)或是PBUF_ROM的memp結(jié)構(gòu),而是直接采用pbuf結(jié)構(gòu)對其進(jìn)行管理。53整理pptPBUF_POOL的內(nèi)存管理PBUF_POOL存儲區(qū)域的結(jié)構(gòu)如下圖,對該類型pbuf的操作與普通鏈表的操作并無不同。每個PBUF_POOL的數(shù)據(jù)緩沖區(qū)都緊跟在pbuf結(jié)構(gòu)后面,并且大小相同。這點(diǎn)與PBUF_ROM不同,因?yàn)镻BUF_ROM的數(shù)據(jù)緩沖區(qū)不在LwIP協(xié)議棧管理的區(qū)域,并且大小不盡相同。54整理pptLwIP移植無RTOS時(shí)的移植LwIP既可以在無RTOS〔RealTimeOperatingSystem,實(shí)時(shí)操作系統(tǒng)〕的環(huán)境下運(yùn)行,也可以很方便地移植到RTOS之上。移植過程中對于LwIP核心模塊沒必要也不建議進(jìn)行修改,而真正的工作是結(jié)合實(shí)際的軟硬件環(huán)境,針對與移植密切相關(guān)的相關(guān)文件與相關(guān)函數(shù)進(jìn)行定制。55整理pptLwIP移植移植函數(shù)為了將LwIP移植到特定的開發(fā)平臺上,需要完成與網(wǎng)絡(luò)接口有關(guān)的底層函數(shù)。這些底層函數(shù)集中在\src\netif\ethernetif.c文件中。建議將“ethernet〞替換成能更好地描述所選網(wǎng)絡(luò)接口的詞匯,如華中科技大學(xué)瑞薩高級嵌入式控制器實(shí)驗(yàn)室自行開發(fā)的RenesasM16C/62P嵌入式開發(fā)平臺采用的網(wǎng)絡(luò)芯片是CS8900A,該文件便用cs8900if.c文件進(jìn)行了替代。文件中但凡用ethernet命名的函數(shù),也一律用cs8900進(jìn)行了替代。LwIP提供的ethernetif.c文件給出了網(wǎng)絡(luò)接口驅(qū)動的整體框架,用戶需要自己完成的函數(shù)主要有3個,分別是底層初始化函數(shù)low_level_init()底層輸入函數(shù)low_level_input()底層輸出函數(shù)low_level_output()。56整理ppt無RTOS時(shí)的移植〔1〕底層初始化函數(shù)low_level_init()原型為staticvoidlow_level_init(structnetif*netif);該函數(shù)用來對網(wǎng)絡(luò)接口進(jìn)行初始化,任何與初始化網(wǎng)絡(luò)接口有關(guān)的操作都可以在該函數(shù)內(nèi)實(shí)現(xiàn)。如對網(wǎng)絡(luò)接口有關(guān)參數(shù)進(jìn)行配置,或是完成網(wǎng)絡(luò)芯片硬件上所需的初始化操作等?!?〕底層輸入函數(shù)low_level_input()函數(shù)原型為staticstructpbuf*low_level_input(structnetif*netif);該函數(shù)為到達(dá)的數(shù)據(jù)包分配pbuf〔通常是一個pbuf鏈〕,并將數(shù)據(jù)包從網(wǎng)絡(luò)接口傳入至pbuf鏈中。數(shù)據(jù)具體接收過程的實(shí)現(xiàn)與網(wǎng)絡(luò)接口硬件有關(guān)。將數(shù)據(jù)裝載至pbbuf時(shí),需對pbuf結(jié)構(gòu)的各字段進(jìn)行正確填充,使其形成邏輯上的pbuf鏈57整理ppt無RTOS時(shí)的移植通常,為收到的數(shù)據(jù)分配的pbuf是PBUF_POOL類型,因?yàn)榉峙湟粋€PBUF_POOL可以很快完成?!?〕底層輸出函數(shù)low_level_output()函數(shù)原型為:staticerr_tlow_level_output(structnetif*netif,structpbuf*p);該函數(shù)實(shí)現(xiàn)真正的的數(shù)據(jù)包發(fā)送過程當(dāng)需要發(fā)送數(shù)據(jù)包時(shí),數(shù)據(jù)包裝載在事先已分配好的pbuf〔鏈〕中。LwIP將pbuf作為參數(shù)傳入給該函數(shù),由該函數(shù)負(fù)責(zé)將數(shù)據(jù)包發(fā)送至指定的網(wǎng)絡(luò)接口中。數(shù)據(jù)具體發(fā)送過程的實(shí)現(xiàn)同樣與網(wǎng)絡(luò)接口硬件有關(guān)。58整理ppt無RTOS時(shí)的移植幾個定時(shí)器函數(shù)在LwIP的移植過程中,注意有幾個定時(shí)器函數(shù)必須每隔固定時(shí)間就調(diào)用一次。具體采用什么機(jī)制實(shí)現(xiàn)這一操作并無限制etharp_tmr()tcp_fasttmr()tcp_slowtmr()這些函數(shù)的運(yùn)行間隔周期可以通過宏定義指定,各函數(shù)的具體定義可在LwIP提供的源碼中找到。59整理pptLwIP在uC/OS-II下的移植為了方便LwIP在RTOS下的移植,屬于操作系統(tǒng)的函數(shù)調(diào)用及數(shù)據(jù)結(jié)構(gòu)并沒有在代碼中直接使用,而是用操作系統(tǒng)模擬層來代替對這些函數(shù)的使用。操作系統(tǒng)模擬層使用統(tǒng)一的接口提供定時(shí)器、進(jìn)程同步及消息傳遞機(jī)制等諸如此類的系統(tǒng)效勞原那么上,移植LwIP只需針對目標(biāo)操作系統(tǒng)修改模擬層實(shí)現(xiàn)即可。60整理pptLwIP在uC/OS-II下的移植模擬層主要實(shí)現(xiàn)以下4大功能:定時(shí)與超時(shí)處理LwIP可以為某一線程注冊假設(shè)干個超時(shí)處理函數(shù),當(dāng)超時(shí)時(shí)限溢出時(shí)便會調(diào)用一個已注冊的函數(shù)。進(jìn)程同步進(jìn)程同步機(jī)制為多個進(jìn)程之間的同步操作提供支持,一般可以用信號量來實(shí)現(xiàn)。如果選用的RTOS不支持信號量,那么可以使如條件變量等其它根本的同步方式來模擬。消息傳遞消息傳遞機(jī)制可通過一種稱作郵箱的抽象方法來實(shí)現(xiàn)。郵箱有兩種根本操作:向郵箱投遞(post)一那么消息和從郵箱中提取(fetch)一那么消息線程管理對LwIP協(xié)議棧的線程進(jìn)行管理和維護(hù),主要指創(chuàng)立線程。61整理ppt移植相關(guān)文件與函數(shù)移植過程中需要創(chuàng)立或修改的源文件和頭文件位于目錄src/arch之下目錄組織結(jié)構(gòu)如下圖:62整理ppt移植相關(guān)文件與函數(shù)頭文件主要是一些宏定義,包括數(shù)據(jù)類型的定義和有關(guān)結(jié)構(gòu)的封裝等;而主要的功能函數(shù)均在sys_arch.c源文件中實(shí)現(xiàn)。此外,sys.c和sys.h兩個文件雖無需作任何修改,但與以上文件〔尤其是sys_arch.c〕關(guān)聯(lián)緊密,有助于更好地理解LwIP在RTOS下的移植實(shí)現(xiàn)。LwIP在設(shè)計(jì)時(shí)就考慮到了將來的RTOS移植問題。為了適應(yīng)不同的操作系統(tǒng),LwIP并沒有在代碼中使用針對某個特定RTOS的系統(tǒng)調(diào)用和數(shù)據(jù)結(jié)構(gòu),而是提供操作系統(tǒng)模擬層作為LwIP和RTOS的一個接口。為了理解LwIP在RTOS下的移植實(shí)現(xiàn)過程,選用嵌入式實(shí)時(shí)操作系統(tǒng)uC/OS-II為例,對LwIP在uC/OS-II下的移植進(jìn)行說明。uC/OS-II是專為嵌入式應(yīng)用設(shè)計(jì)的實(shí)時(shí)內(nèi)核,關(guān)于其詳細(xì)信息可參考其官網(wǎng)://micrium/page/home。實(shí)現(xiàn)LwIP在uC/OS-II下的移植,其主要工作就是結(jié)合LwIP和uC/OS-II的特點(diǎn),對操作系統(tǒng)模擬層進(jìn)行修改和定制,使LwIP和uC/OS-II無縫連接。63整理ppt移植相關(guān)文件與函數(shù)根據(jù)LwIP源碼提供的sys_arch.txt文件,需要實(shí)現(xiàn)的函數(shù)有:voidsys_init(void)被調(diào)用來初始化操作系統(tǒng)模擬層。sys_sem_tsys_sem_new(u8_tcount)創(chuàng)立并返回一個新的信號量,參數(shù)count指定信號量的初始狀態(tài)。voidsys_sem_free(sys_sem_tsem)刪除一個信號量。voidsys_sem_signal(sys_sem_tsem)發(fā)出一個信號量。u32_tsys_arch_sem_wait(sys_sem_tsem,u32_ttimeout)等待一個信號量,該操作會阻塞調(diào)用該函數(shù)的線程。sys_mbox_tsys_mbox_new(void)創(chuàng)立一個空的郵箱。voidsys_mbox_free(sys_mbox_tmbox)刪除一個郵箱。64整理ppt移植相關(guān)文件與函數(shù)voidsys_mbox_post(sys_mbox_tmbox,void*msg)向指定的郵箱發(fā)送一那么消息。u32_tsys_arch_mbox_fetch(sys_mbox_tmbox,void**msg,u32_ttimeout)從郵箱中提取一那么消息,該操作同樣會阻塞調(diào)用該函數(shù)的線程。structsys_timeouts*sys_arch_timeouts(void)返回指向當(dāng)前線程的sys_timeouts結(jié)構(gòu)的指針。LwIP的每個線程都有自己的超時(shí)等待屬性,每個線程都分配了一個超時(shí)等待的數(shù)據(jù)結(jié)構(gòu)sys_timeout,并把這個數(shù)據(jù)結(jié)構(gòu)存放于鏈表sys_timeouts中。該函數(shù)的作用是通過查詢來獲得一個指向當(dāng)前線程使用的sys_timeouts結(jié)構(gòu)的指針。sys_thread_tsys_thread_new(void(*thread)(void*arg),void*arg,intprio)創(chuàng)立一個新的LwIP線程。65整理ppt超時(shí)處理的實(shí)現(xiàn)如前所述,LwIP的每個線程都有自己的超時(shí)等待屬性。為了順利理解LwIP的這一機(jī)制,先引入與之相關(guān)的幾種數(shù)據(jù)結(jié)構(gòu)。sys_timeout是線程的超時(shí)等待數(shù)據(jù)結(jié)構(gòu),其內(nèi)部結(jié)構(gòu)定義如下:structsys_timeout{structsys_timeout*next; //指向鏈表中的下一個sys_timeoutu32_ttime; //超時(shí)時(shí)限〔ms〕sys_timeout_handlerh; //超時(shí)處理函數(shù)void*arg; //超時(shí)處理函數(shù)的參數(shù)};其中sys_timeout_handler是指向超時(shí)處理函數(shù)的指針,其定義為typedefvoid(*sys_timeout_handler)(void*arg);多個sys_timeout可以鏈接成一個鏈表,如下圖:66整理ppt超時(shí)處理的實(shí)現(xiàn)sys_timeouts是sys_timeout鏈表的表頭,它只包含一個元素,即指向sys_timeout結(jié)構(gòu)的指針,其定義如下:structsys_timeouts{structsys_timeout*next; //指向鏈表第一個sys_timeout};加上sys_timeouts結(jié)構(gòu)后,LwIP線程的超時(shí)等待鏈表結(jié)構(gòu)如下圖:67整理ppt超時(shí)處理的實(shí)現(xiàn)68整理ppt超時(shí)處理的實(shí)現(xiàn)timeoutlist將一個sys_timeouts結(jié)構(gòu)和優(yōu)先級聯(lián)系在一起,這樣便于根據(jù)當(dāng)前優(yōu)先級查找對應(yīng)的sys_timeouts鏈表,其定義如下:structtimeoutlist{structsys_timeoutstimeouts; //超時(shí)等待鏈表INT8Uprio; //優(yōu)先級};每個線程都有一個對以的timeoutlist結(jié)構(gòu),通過該結(jié)構(gòu)的timeouts元素可以定位超時(shí)等待列表的表頭,從而確定該線程的所有超時(shí)處理函數(shù),69整理ppt超時(shí)處理的實(shí)現(xiàn)LwIP在RTOS上的移植過程中需要實(shí)現(xiàn)的與超時(shí)處理有關(guān)的函數(shù)是sys_arch_timeouts()?!?〕移植函數(shù)sys_arch_timeouts()sys_arch_timeouts()函數(shù)的作用是通過查詢機(jī)制,獲取指向當(dāng)前線程的sys_timeouts結(jié)構(gòu)的指針,相當(dāng)于定位超時(shí)等待鏈表的表頭。函數(shù)的原型如下:structsys_timeouts*sys_arch_timeouts(void);該函數(shù)外表上沒有參數(shù),但實(shí)際上調(diào)用該函數(shù)的線程有自己的優(yōu)先級,因此可以利用當(dāng)前線程的優(yōu)先級充當(dāng)函數(shù)的隱含參數(shù)。這樣處理帶來的限制是一個線程不能通過調(diào)用該函數(shù)來獲取另一個線程的sys_timeouts結(jié)構(gòu),但這一般不會引起什么問題。70整理ppt超時(shí)處理的實(shí)現(xiàn)sys_timeouts結(jié)構(gòu)和當(dāng)前線程的優(yōu)先級一起封裝在timeoutlist結(jié)構(gòu)中。為了存儲線程的timeoutlist結(jié)構(gòu),在sys_arch.c文件中定義了一個timeoutlist數(shù)組:staticstructtimeoutlisttimeoutlist[LWIP_MAX_TASKS];LWIP_MAX_TASKS是最大的LwIP線程數(shù),可以事先進(jìn)行配置。每次調(diào)用sys_thread_new()創(chuàng)立一個新的線程時(shí),都會依序取出一個數(shù)組元素,用當(dāng)前線程的優(yōu)先級對數(shù)組元素的prio字段進(jìn)行填充。sys_arch_timeouts()函數(shù)通過線性搜索的方法對數(shù)組元素進(jìn)行遍歷,直到發(fā)現(xiàn)某個數(shù)組元素的prio字段與當(dāng)前優(yōu)先級相同為止,而該數(shù)組元素的timeouts字段正是我們需要的目標(biāo)。71整理ppt超時(shí)處理的實(shí)現(xiàn)72整理ppt超時(shí)處理的實(shí)現(xiàn)〔2〕相關(guān)函數(shù)sys_timeout()sys_timeout()函數(shù)用以向當(dāng)前線程增加一個超時(shí)處理函數(shù),其原型如下:voidsys_timeout(u32_tmsecs,sys_timeout_handlerh,void*arg);sys_timeouts()函數(shù)首先從內(nèi)存中申請一塊空間,以存放一個sys_timeout結(jié)構(gòu)。如申請成功那么利用函數(shù)的實(shí)參對結(jié)構(gòu)的各字段進(jìn)行填充。要向當(dāng)前線程注冊一個超時(shí)處理函數(shù),sys_timeouts()會通過sys_arch_timeouts()函數(shù)獲取當(dāng)前線程的sys_timeouts結(jié)構(gòu)。73整理ppt超時(shí)處理的實(shí)現(xiàn)第一次調(diào)用sys_timeout()注冊一個超時(shí)處理函數(shù)時(shí),直接將sys_timeout結(jié)構(gòu)鏈接在當(dāng)前線程的sys_timeouts結(jié)構(gòu)即可,如下圖:74整理ppt超時(shí)處理的實(shí)現(xiàn)應(yīng)用程序可能會屢次注冊超時(shí)處理函數(shù)或刪除超時(shí)處理函數(shù),這樣處理后一個線程的sys_timeouts鏈表中可能會同時(shí)存在多個sys_timeout結(jié)構(gòu)。在這種情況下,向線程添加一個超時(shí)處理函數(shù)略微復(fù)雜,因?yàn)閟ys_timeout結(jié)構(gòu)必須插入到鏈表的恰當(dāng)位置。實(shí)際上如果一個線程有多個超時(shí)處理函數(shù),LwIP會按照鏈表的邏輯順序依次結(jié)算。這里所謂恰當(dāng)?shù)奈恢茫褪潜容^當(dāng)前鏈表節(jié)點(diǎn)的超時(shí)時(shí)限和待插入節(jié)點(diǎn)的超時(shí)時(shí)限,保證插入該節(jié)點(diǎn)后不會影響原有任一節(jié)點(diǎn)的超時(shí)等待屬性。75整理ppt超時(shí)處理的實(shí)現(xiàn)如下圖,假設(shè)當(dāng)前線程已注冊3個超時(shí)處理函數(shù),對應(yīng)有3個sys_timeout結(jié)構(gòu),其超時(shí)時(shí)限分別是time1=100,time2=40,time3=80。現(xiàn)要注冊一個超時(shí)時(shí)限為time4=160的超時(shí)處理函數(shù)。為了確定恰當(dāng)?shù)牟迦胛恢?,可以沿著鏈表逐次推算超時(shí)時(shí)限,分析過程如下:1time1<time4→next4在next1之后2time1+time2<time4→next4在next2之后3time1+time2+time3>time4→next4在next3之前經(jīng)以上步驟,next4的位置已經(jīng)確定,即位于next2和next3之間。注意插入next4節(jié)點(diǎn)后,next4節(jié)點(diǎn)及緊挨在next4后面的next3節(jié)點(diǎn)的time屬性值需做對應(yīng)調(diào)整,調(diào)整后的結(jié)果如下圖:76整理ppt超時(shí)處理的實(shí)現(xiàn)77整理ppt超時(shí)處理的實(shí)現(xiàn)如果新節(jié)點(diǎn)next4的超時(shí)時(shí)限time4取其它值,那么可能會出現(xiàn)一些特殊情況。time4<time1,即新節(jié)點(diǎn)的time值比第一個節(jié)點(diǎn)還小。這種情況直接將next4節(jié)點(diǎn)插入到next1節(jié)點(diǎn)之前,并調(diào)整time1=time1-time4即可。78整理ppt超時(shí)處理的實(shí)現(xiàn)time4=time1+time2,即新節(jié)點(diǎn)的time值等于前面假設(shè)干節(jié)點(diǎn)他time之和。這種情況next4將插入到next2的后面。next4節(jié)點(diǎn)的time值調(diào)整為0,而與next4相鄰的next2節(jié)點(diǎn)和next3節(jié)點(diǎn)那么無需調(diào)整time屬性。線程在依序處理超時(shí)等待函數(shù)過程中,一旦執(zhí)行完next2節(jié)點(diǎn)的超時(shí)處理函數(shù)h2(arg2),會立即執(zhí)行next4節(jié)點(diǎn)的超時(shí)處理函數(shù)h4(arg4)。time4>time1+time2+time3,即新節(jié)點(diǎn)的time值大于現(xiàn)有所有節(jié)點(diǎn)time之和。這種情況next4節(jié)點(diǎn)將插入到最后,并調(diào)整time4=time4-time1-time2-time3,next4=NULL。79整理ppt超時(shí)處理的實(shí)現(xiàn)〔3〕相關(guān)函數(shù)sys_untimeout()sys_untimeout()函數(shù)與sys_timeout()函數(shù)的作用恰好相反,用以刪除當(dāng)前線程某一指定的超時(shí)處理函數(shù)。函數(shù)原型如下:voidsys_untimeout(sys_timeout_handlerh,void*arg);與sys_timeout()相比,sys_untimeout()函數(shù)同樣會調(diào)用sys_arch_timeouts()獲取當(dāng)前線程的sys_timeouts鏈表結(jié)構(gòu)。函數(shù)通過一種簡單的線性搜索的方法,從表頭開始遍歷,直到找到一個超時(shí)處理函數(shù)h和參數(shù)arg均符合的sys_timeout結(jié)構(gòu)。將該結(jié)構(gòu)所在的節(jié)點(diǎn)從鏈表中刪除,并調(diào)整緊挨其后的節(jié)點(diǎn)〔如果有的話〕的超時(shí)時(shí)限屬性,最后釋放該結(jié)構(gòu)占用的內(nèi)存。80整理ppt超時(shí)處理的實(shí)現(xiàn)假設(shè)某一線程的超時(shí)處理函數(shù)鏈表如下圖:81整理ppt超時(shí)處理的實(shí)現(xiàn)如果線程希望刪除h2處理函數(shù),即執(zhí)行sys_untimeout(h2,arg2);next2節(jié)點(diǎn)將從原鏈表中刪除,同時(shí)next3節(jié)點(diǎn)的time3將會調(diào)整為time3=time3+time2。調(diào)整后的狀態(tài)為:82整理ppt超時(shí)處理的實(shí)現(xiàn)但如果線程不是要刪除h2處理函數(shù),而是要刪除最后一個超時(shí)處理函數(shù),即執(zhí)行sys_untimeout(h3,arg3);這種情況next3節(jié)點(diǎn)從鏈表中刪除后,沒有后續(xù)節(jié)點(diǎn)需要調(diào)整超時(shí)時(shí)限屬性。結(jié)果如下:83整理ppt超時(shí)處理的實(shí)現(xiàn)〔4〕超時(shí)處理函數(shù)的使用在等待信號量或等待消息的過程中,LwIP會對超時(shí)等待鏈表中的超時(shí)處理函數(shù)進(jìn)行處理。對一個線程來講,要么通過調(diào)用sys_sem_wait()等待一個信號量,要么通過調(diào)用sys_mbox_fetch()等待一那么消息,至少要采取一種方法阻塞當(dāng)前線程,否那么注冊的超時(shí)處理函數(shù)將無法正常執(zhí)行。鑒于郵箱結(jié)構(gòu)比信號量結(jié)構(gòu)占用更多的資源,因此通常通過永久等待一個信號量來實(shí)現(xiàn)線程阻塞。如需每隔一定周期就執(zhí)行一次某函數(shù),那么必須在超時(shí)處理函數(shù)中重新注冊自己。例如需要每隔250ms就執(zhí)行一次tcp_tmr(),通??梢圆捎孟旅娴姆绞綄?shí)現(xiàn)://向當(dāng)前線程注冊一個超時(shí)處理函數(shù)sys_timeout((u32_t)OS_TICKS_PER_SEC/4,(sys_timeout_handler)TCP_Timer,NULL);……//如需周期執(zhí)行tcp_tmr〔〕,那么需在TCP_Timer〔〕中重新注冊自己voidTCP_Timer(void*p_arg){ tcp_tmr();//每隔250ms執(zhí)行一次 sys_timeout((u32_t)OS_TICKS_PER_SEC/4,(sys_timeout_handler)TCP_Timer,NULL);}84整理ppt進(jìn)程同步的實(shí)現(xiàn)進(jìn)程同步機(jī)制是任務(wù)之間通信的一種重要方式,通??梢杂尚盘柫繉?shí)現(xiàn)。uC/OS-II對信號量有較全面的支持,因此移植過程中比較方便實(shí)現(xiàn)。uC/OS-II實(shí)現(xiàn)了信號量和互斥型信號量,這里采用uC/OS-II的信號量實(shí)現(xiàn)。由于uC/OS-II支持信號量的各種操作,并且可以滿足LwIP對信號量的要求,因此只需對相關(guān)結(jié)構(gòu)和函數(shù)進(jìn)行重新封裝即可。85整理ppt進(jìn)程同步的實(shí)現(xiàn)函數(shù)sys_sem_wait()

該函數(shù)是由LwIP應(yīng)用程序調(diào)用的用來等待一個信號量的函數(shù),但它會在等待信號量的過程中對當(dāng)前線程的超時(shí)等待函數(shù)進(jìn)行處理。函數(shù)原型如下:

voidsys_sem_wait(sys_sem_tsem)該函數(shù)首先調(diào)用sys_arch_timeouts()獲取當(dāng)前線程的超時(shí)等待函數(shù)鏈表,以對超時(shí)等待鏈表中的超時(shí)處理函數(shù)依次結(jié)算。真正實(shí)現(xiàn)等待一個信號量的過程由sys_arch_sem_wait()完成。現(xiàn)仍以下面的超時(shí)等待鏈表為例,分析sys_sem_wait()在等待信號量過程中對超時(shí)處理函數(shù)的處理。86整理ppt進(jìn)程同步的實(shí)現(xiàn)1執(zhí)行sys_arch_sem_wait(sem,time1)。如超時(shí)溢出那么說明在time1時(shí)間內(nèi)一直未成功等到信號量,此時(shí)執(zhí)行超時(shí)處理函數(shù)h1(arg1),同時(shí)將next1節(jié)點(diǎn)從鏈表中刪除,并轉(zhuǎn)到步驟2。如在time1時(shí)間內(nèi)成功等到信號量,那么不管實(shí)際消耗的等待時(shí)間是多少,LwIP一律認(rèn)為消耗時(shí)間為1ms,并調(diào)整time1=time1-1,此時(shí)轉(zhuǎn)到步驟4。2執(zhí)行sys_arch_sem_wait(sem,time2)。只有在time1時(shí)限耗盡的情況下,才會執(zhí)行sys_arch_sem_wait(sem,time2)。與1類似,如未等到信號量那么執(zhí)行h2(arg2)并轉(zhuǎn)到步驟3,否那么調(diào)整time2=time2-1并轉(zhuǎn)到步驟4。87整理ppt進(jìn)程同步的實(shí)現(xiàn)3調(diào)用sys_arch_sem_wait(sem,time3)。只有在next3節(jié)點(diǎn)前面的所有節(jié)點(diǎn)的超時(shí)時(shí)限均已耗盡的情況下,才會執(zhí)行sys_arch_sem_wait(sem,time3)。由于next3已經(jīng)是最后一個節(jié)點(diǎn),因此不管成功等到信號量與否,均會轉(zhuǎn)到步驟4。4sys_sem_wait()函數(shù)返回或作永久等待。如果成功等到了信號量,sys_sem_wait()函數(shù)返回。但如果超時(shí)等待鏈表中所有超時(shí)時(shí)限均已耗盡且所有超時(shí)處理函數(shù)均已執(zhí)行后,仍未等到信號量,那么sys_sem_wait()會調(diào)用sys_arch_sem_wait(0)一直等到信號量有效為止。88整理ppt進(jìn)程同步的實(shí)現(xiàn)一種特殊情況是當(dāng)前線程超時(shí)等待鏈表為空,也就是沒有超時(shí)等待函數(shù)。sys_sem_wait()會直接調(diào)用sys_arch_sem_wait(0)做永久等待。另一種情況是在等待信號量的過程中發(fā)現(xiàn)某一節(jié)點(diǎn)的超時(shí)時(shí)限time=0。說明該節(jié)點(diǎn)的超時(shí)時(shí)限已經(jīng)耗盡,需立即執(zhí)行節(jié)點(diǎn)對應(yīng)的超時(shí)處理函數(shù)h(arg)。注意time=0與sys_timeouts鏈表為空是截然不同的:time=0只是說明該節(jié)點(diǎn)的超時(shí)時(shí)限已耗盡sys_timeouts為空那么意味著當(dāng)前線程沒有任何函數(shù)需要做超時(shí)等待。89整理ppt消息傳遞的實(shí)現(xiàn)消息傳遞是任務(wù)之間通信的另一種重要方式,通常使用一種稱為郵箱的抽象方法來實(shí)現(xiàn)。郵箱有兩種根本的操作:郵遞(post)〔發(fā)送一那么消息〕操作不會阻塞進(jìn)程提取(fetch)〔等待一那么消息〕操作可能會阻塞進(jìn)程。uC/OS-II提供了消息郵箱和消息隊(duì)列兩種機(jī)制,區(qū)別是消息郵箱一次只能處理一那么消息,而消息隊(duì)列可以存儲多那么消息。為了使LwIP更好地運(yùn)作,采用uC/OS-II的消息隊(duì)列實(shí)現(xiàn)LwIP所需的消息傳遞機(jī)制。90整理ppt線程管理的實(shí)現(xiàn)在線程管理方面,LwIP只提供了創(chuàng)立線程的操作。由于uC/OS-II沒有采用“線程〞這一概念,而是采用“任務(wù)〞的概念,LwIP的線程管理實(shí)際上是通過uC/OS-II的任務(wù)管理機(jī)制實(shí)現(xiàn)的。每個線程都有自己的超時(shí)等待屬性。為了區(qū)別不同線程的超時(shí)等待屬性,在創(chuàng)立線程的過程中會將優(yōu)先級prio填入到一個timeoutlist結(jié)構(gòu)的prio成員中,如下圖:91整理ppt線程管理的實(shí)現(xiàn)由于uC/OS-II中每個任務(wù)都具有唯一的優(yōu)先級,因此prio可以作為LwIP線程的一個標(biāo)識,以區(qū)分不同的線程。實(shí)際上sys_arch_timeouts()正是通過這一標(biāo)識來定位當(dāng)前線程的超時(shí)等待鏈表的。92整理pptLwIP網(wǎng)絡(luò)編程應(yīng)用實(shí)例為了對LwIP的移植和應(yīng)用進(jìn)行測試和驗(yàn)證,以一個具體的應(yīng)用實(shí)例來說明LwIP網(wǎng)絡(luò)編程的一般方法。目的是設(shè)計(jì)和實(shí)現(xiàn)一個簡單的嵌入式WEB效勞器,該WEB效勞器可以響應(yīng)來自瀏覽器的HTTPGET請求,并在發(fā)送請求的瀏覽器上顯示一個小型頁面。93整理ppt實(shí)驗(yàn)平臺準(zhǔn)備硬件平臺的一個最根本要求是提供對以太網(wǎng)接口的支持。選用的是華中科技大學(xué)瑞薩高級嵌入式控制器實(shí)驗(yàn)室自主研發(fā)制作的RenesasM16C/62P嵌入式開發(fā)平臺。該平臺采用瑞薩科技(RENESAS)的M16C/62P單片機(jī)作為主控制器,通過集成一塊CS8900A網(wǎng)絡(luò)芯片來實(shí)現(xiàn)網(wǎng)絡(luò)數(shù)據(jù)收發(fā)功能。94整理ppt實(shí)驗(yàn)平臺準(zhǔn)備軟件平臺最重要的局部是開發(fā)環(huán)境。采用Renesas的High-performanceEmbeddedWorkshop進(jìn)行編程開發(fā)。為了方便調(diào)試,華中科技大學(xué)瑞薩高級嵌入式控制器實(shí)驗(yàn)室開發(fā)了專門針對RenesasM16C/62P單片機(jī)的監(jiān)控程序。通過該監(jiān)控程序,將用戶應(yīng)用程序下載至ROM或者RAM,可以實(shí)現(xiàn)調(diào)試功能95整理ppt嵌入式WEB效勞器的設(shè)計(jì)瀏覽器訪問WEB效勞器所使用的是HTTP協(xié)議??蛻簟瞁EB效勞器〕通過HTTP協(xié)議向效勞器發(fā)送請求效勞器根據(jù)HTTP協(xié)議對客戶端發(fā)來的請求進(jìn)行解碼,并對其作出應(yīng)答。HTTP使用TCP作為運(yùn)輸層,客戶在向效勞器發(fā)送請求之前,要先與效勞器的IP地址在端口80〔HTTP的知名端口〕建立一個連接。效勞器在端口80偵聽進(jìn)入的連接,并接受和處理客戶的請求。由于只是對LwIP協(xié)議棧進(jìn)行測試和驗(yàn)證,因此設(shè)計(jì)的WEB效勞器只對客戶端的GET請求作出應(yīng)答,而對其它請求一概不予理會。96整理ppt嵌入式WEB效勞器的設(shè)計(jì)瀏覽器與WEB效勞器交互的示意圖。圖中瀏覽器運(yùn)行在PC機(jī)〔或支持瀏覽器的其它設(shè)備〕上,WEB效勞器運(yùn)行在RenesasM16C/62P嵌入式開發(fā)平臺上,二者通過網(wǎng)絡(luò)進(jìn)行連接。所有的數(shù)據(jù)交互過程受TCP/IP協(xié)議族的制約。97整理ppt嵌入式WEB效勞器的實(shí)現(xiàn)在進(jìn)行了必要的初始化工作后,翻開TCP的80端口并對該端口進(jìn)行偵聽。一旦客戶發(fā)起請求,那么效勞器接受并解析該請求。如果請求正確,那么效勞器將相應(yīng)的頁面內(nèi)容發(fā)送給客戶端,而客戶端〔通常是瀏覽器〕將該頁面直觀地顯示出來。至此,一次完整的交互過程已完成。效勞器或者繼續(xù)偵聽更多的請求,或者主動關(guān)閉。98整理ppt主流程圖99整理ppt主要程序的實(shí)現(xiàn)〔1〕HTTP主線程HTTP的主線程首先注冊一個新的TCP連接,并將其綁定到80端口。隨后該連接進(jìn)入偵聽的狀態(tài),一旦接受到客戶發(fā)起的連接請求,那么調(diào)用process_connection()函數(shù)進(jìn)行處理。主要程序代碼如下:staticvoidd_thread(void*arg){ structnetconn*conn,*newconn;

/*CreateanewTCPconnectionhandle.*/ conn=netconn_new(NETCONN_TCP);100整理ppt主要程序的實(shí)現(xiàn)

/*Bindtheconnectiontoport80onany localIPaddress.*/ netconn_bind(conn,NULL,80);

/*PuttheconnectionintoLISTENstate.*/ netconn_listen(conn);

/*Loopforever.*/ while(1) { /*Acceptanewconnection.*/ newconn=netconn_accept(conn); if(newconn!=NULL) { /*Processtheincommingcon

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論