嵌入式平臺中配置雙協(xié)議棧的問題
最近有不少網(wǎng)友問到如何進行那個配置雙協(xié)議棧的問題。我們可以來從下面的文章中做一個具體的了解。我們都知道,網(wǎng)絡(luò)的發(fā)展速度驚人,格式的功能以及應(yīng)用令人眼花繚亂。在這些功能以及應(yīng)用的背后,是眾多網(wǎng)絡(luò)協(xié)議的支持。那么這里我們來重點講解一下Windows平臺上使用Visual C++ 6.0開發(fā)環(huán)境進行嵌入式TCP/IP協(xié)議棧的開發(fā)和仿真調(diào)試手段。詳細講解了如何使用Winpcap接收和發(fā)送IP數(shù)據(jù)報文以及在Windows上配置雙協(xié)議棧的一些問題。
1 引言
隨著Internet的廣泛的應(yīng)用,在嵌入式設(shè)備中支持TCP/IP協(xié)議以連接到Internet網(wǎng)絡(luò)并與外界通信的需求更加強烈,這就需要在嵌入式系統(tǒng)中支持TCP/IP協(xié)議棧.雖然目前的商用嵌入式操作系統(tǒng),如VxWorks、QNX、pSOS、VRTX等,均提供基于TCP/IP的網(wǎng)絡(luò)組件,但為了滿足各個方面的應(yīng)用需要,其實現(xiàn)過于復(fù)雜,需要占用大量的系統(tǒng)資源.而嵌入式系統(tǒng)的本身資源有限,并且其應(yīng)用和功能比較單一,具有較強的針對性,因此也并不需要一個完整的TCP/IP網(wǎng)絡(luò)協(xié)議組件,只需要實現(xiàn)與需求相關(guān)的部分協(xié)議,不使用的協(xié)議則不需要支持.在另一方面,對于某些特定的嵌入式系統(tǒng),甚至需要優(yōu)化TCP/IP協(xié)議棧或者在TCP/IP協(xié)議棧中編寫自己需要的網(wǎng)絡(luò)協(xié)議.那些不能提供開放源碼的商用嵌入式系統(tǒng)的TCP/IP協(xié)議棧都很難滿足用戶的配置需求,需要用戶自行開發(fā)和定制適合自己系統(tǒng)需求的嵌入式TCP/IP協(xié)議棧.
2 嵌入式協(xié)議棧的開發(fā)和調(diào)試問題
一般的嵌入式系統(tǒng)的開發(fā)和調(diào)試都是使用其相應(yīng)的開發(fā)調(diào)試工具連接計算機和目標機進行交叉開發(fā)和調(diào)試.例如被廣泛使用的VxWorks嵌入式實時操作系統(tǒng)的開發(fā)工具Tornado,它就是一套強有力的交叉開發(fā)工具,用戶可以在計算機上使用圖形界面對目標機上的應(yīng)用程序進行調(diào)試.
但即便是使用像Tornado這樣優(yōu)秀的嵌入式開發(fā)環(huán)境,在交叉調(diào)試協(xié)議棧此類比較大型的程序時,還是顯得力不從心,其開發(fā)調(diào)試是件費時費力的工作,大大增加了系統(tǒng)的開發(fā)難度和開發(fā)調(diào)試的周期.在目前的嵌入式系統(tǒng)的調(diào)試工具還不盡如人意的現(xiàn)狀下,對嵌入式TCP/IP協(xié)議棧的開發(fā)如果能前期在Windows平臺上進行開發(fā)和仿真調(diào)試,將是一件很有意義的工作.
嵌入式TCP/IP協(xié)議棧雖然是基于嵌入式操作系統(tǒng),但除了接收和發(fā)送數(shù)據(jù)包以外,幾乎并不直接與底層硬件打交道.因此在Windows平臺上仿真調(diào)試和運行TCP/IP協(xié)議棧是完全可行的,可以完成絕大部分功能的開發(fā)與調(diào)試,后期再移植到嵌入式系統(tǒng)上,只需進一步稍加調(diào)試和測試便能實現(xiàn)整個嵌入式軟件系統(tǒng)的功能和性能.這樣的開發(fā)流程能夠極大的提高開發(fā)的效率,減少開發(fā)的周期.
3 在Windows平臺上運行嵌入式協(xié)議棧
在講解配置雙協(xié)議棧之前,我們來了解一下在Windows平臺上運行嵌入式協(xié)議棧的內(nèi)容。在Windows平臺上仿真調(diào)試和運行TCP/IP協(xié)議棧,首先需要在Visual C++ 6.0開發(fā)環(huán)境中創(chuàng)建一個Win32應(yīng)用程序的項目工程用于模擬嵌入式系統(tǒng),嵌入式TCP/IP協(xié)議棧就是在這個Win32的應(yīng)用程序中運行.這樣,我們使用Windows平臺下的一個進程模擬了一個多任務(wù)的嵌入式操作系統(tǒng).
一個多任務(wù)嵌入式操作系統(tǒng)需要具有任務(wù)管理、內(nèi)存管理以及任務(wù)間通信機制如信號量、消息隊列等功能.因此,如想在Windows平臺上運行嵌入式TCP/IP協(xié)議棧,也必須提供上述多任務(wù)嵌入式操作系統(tǒng)的基本功能.
在多任務(wù)嵌入式操作系統(tǒng)中,任務(wù)是系統(tǒng)進行調(diào)度的最基本的單元,參與資源競爭和CPU資源在任務(wù)間的分配,系統(tǒng)通過循環(huán)的方式為每個任務(wù)安排一定的 CPU時間片,而在宏觀上看仿佛是若干任務(wù)并發(fā)處理,形成多任務(wù)操作系統(tǒng).而在Winodows這樣的通用操作系統(tǒng)平臺上,則是由線程作為參與CPU時間 片資源競爭最小實體,因此,我們使用線程模擬嵌入式操作系統(tǒng)中的一個任務(wù).任務(wù)的創(chuàng)建、刪除和控制等操作通過調(diào)用Windows平臺中提供的線程的創(chuàng)建、 刪除和控制的Win32 API函數(shù)來實現(xiàn).
在多任務(wù)操作系統(tǒng)中,任務(wù)與任務(wù)之間需要協(xié)調(diào)動作,相互配合,這就需要提供任務(wù)間相互通信的機制以進行同步和互斥.嵌入式系統(tǒng)中一般提供信號量、事件和消 息機制這三種主要的任務(wù)間通信手段.同樣,在Windows平臺上的Win32 API也提供相應(yīng)的用于進程/線程間通信的信號量、事件和消息機制的函數(shù).#p#
由于Windows是一個強大的通用分時操作系統(tǒng),能夠提供完善的操 作系統(tǒng)接口.因此,多任務(wù)嵌入式操作系統(tǒng)完全可以在Windows平臺上模擬.不過,這種模擬也只是近似的,畢竟對于多數(shù)嵌入式系統(tǒng)都是實時系統(tǒng),而 Windows卻是分時系統(tǒng),無法保證其系統(tǒng)的實時性.
想要對配置雙協(xié)議棧有所掌握,肯定是要了解TCP/IP協(xié)議棧的開發(fā)的。至于嵌入式TCP/IP協(xié)議棧的開發(fā),考慮TCP/IP協(xié)議族的復(fù)雜性以及其協(xié)議棧龐大的代碼量,試圖完全從頭到尾徹底的重新編寫一套TCP/IP協(xié)議棧的代碼是極為艱難的,需要大量的人力、物力和時間的投入.其實目前TCP/IP技術(shù)已經(jīng)十分成熟,幾乎所有的通用操作系統(tǒng)都提供TCP/IP協(xié)議棧用于網(wǎng)絡(luò)支持,包括那些公開源碼的操作系統(tǒng).因此考慮移植源碼公開的TCP/IP協(xié)議棧,同時根據(jù)需求對其進行適量的精簡和改進.
目前,比較常見的源碼公開的TCP/IP協(xié)議棧軟件有:
1). BSD Net網(wǎng)絡(luò)協(xié)議棧軟件.這是由加利福利亞大學(xué)伯克利分校計算機系統(tǒng)研究小組發(fā)布的,世界上***個被廣泛應(yīng)用TCP/IP軟件版本就是伯克利于1983年發(fā)布的4.2BSD,有許多系統(tǒng)的TCP/IP協(xié)議棧實現(xiàn)都是以它的源代碼為基礎(chǔ)而開發(fā)的.目前其***版本是1994年發(fā)布的4.4BSD-Lite2,又稱為Net/3.
2). Linux的TCP/IP協(xié)議棧軟件.作為一個遵循GUN公共許可協(xié)議,源碼全部公開的自由操作系統(tǒng)軟件,其TCP/IP協(xié)議棧部分源碼是以BSD的網(wǎng)絡(luò)協(xié)議棧為模型,支持BSD的Socket接口,但其內(nèi)部代碼是重新寫的,與4.4BSD-Lite2并不雷同.
3). lwIP是一個比較小型的源碼開放的TCP/IP協(xié)議棧軟件,是由瑞典計算機科學(xué)研究院的Adam Dunkels教授編寫.它只需要10K的RAM空間和40K的ROM存儲空間,因此非常適合嵌入式系統(tǒng)里使用.
4). uIP則是一個超小型的TCP/IP協(xié)議棧,僅能提供ARP、SLIP、TCP、ICMP和IP這幾種基本的協(xié)議.其所需資源非常的少,所以非常適合在8位和16位單片機上運行.
對于TCP/IP協(xié)議棧的選擇主要根據(jù)用戶本身的需求和所能提供的軟硬件資源來確定.比如像BSD和Linux的TCP/IP協(xié)議棧屬于通用的協(xié)議棧,支持協(xié)議比較齊全,但也需要耗用大量的ROM和RAM存儲空間,對CPU的要求也比較高;而lwIP和uIP這類的協(xié)議棧是專門為嵌入式操作系統(tǒng)開發(fā)出來的,軟件結(jié)構(gòu)比較緊湊,對CPU和存儲器需求不高,但其所支持的協(xié)議種類及功能也非常有限.
4 WinPcap工具包介紹
在Windows平臺上仿真調(diào)試和運行TCP/IP協(xié)議棧,還需要考慮協(xié)議棧如何接收和發(fā)送數(shù)據(jù)報文的問題,這就需要使用WinPcap來實現(xiàn).
WinPcap(Windows Packet Capture)是Windows平臺下一個公共的、免費的網(wǎng)絡(luò)訪問系統(tǒng),能為Win32應(yīng)用程序提供網(wǎng)絡(luò)訪問的能力.它提供以下四項主要功能:
1) 捕獲原始數(shù)據(jù)報文,包括共享網(wǎng)絡(luò)上各主機發(fā)送/接收和相互交換的數(shù)據(jù)包;
2) 在數(shù)據(jù)報文發(fā)送往應(yīng)用程序之前,按照自定義的規(guī)則將某些特定的數(shù)據(jù)包過濾掉;
3) 在網(wǎng)絡(luò)上發(fā)送原始的數(shù)據(jù)報文;
4) 收集網(wǎng)絡(luò)通信過程中的統(tǒng)計信息;
WinPcap的主要功能在于獨立于主機協(xié)議而發(fā)送和接收原始數(shù)據(jù)報文,能夠監(jiān)聽共享網(wǎng)絡(luò)上傳送的數(shù)據(jù)包.因此,通過調(diào)用它提供的各種函數(shù),可以實現(xiàn)在 Windows平臺下將各類數(shù)據(jù)報文通過網(wǎng)絡(luò)適配器發(fā)送到共享網(wǎng)絡(luò)上去,同樣也可以接收網(wǎng)絡(luò)適配器上收到的各種原始的數(shù)據(jù)包.
要使用WinPcap,首先需要在Windows平臺上安裝WinPcap驅(qū)動軟件,然后便可以在Win32的應(yīng)用程序中通過包含packet32.h這 個頭文件來使用由WinPcap的動態(tài)鏈接庫packet32.dll或者靜態(tài)鏈接庫packet32.lib所提供的庫函數(shù)來對網(wǎng)絡(luò)適配器進行打開、設(shè) 置、關(guān)閉操作和通過網(wǎng)絡(luò)適配器進行接收或者發(fā)送數(shù)據(jù)報文.#p#
下面簡要介紹一下其主要函數(shù)的功能:
1) BOOLEAN PacketGetAdapterNames(LPSTR pStr,PULONG BufferSize) 返回可以得到的網(wǎng)絡(luò)適配器列表及描述.
2) LPADAPTER PacketOpetAdapter(LPTSTR AdapterName) 打開一個網(wǎng)絡(luò)適配器.
3) BOOLEAN PacketSetBuff(LPADAPTER AdapterObject,int dim) 設(shè)置捕獲數(shù)據(jù)報的內(nèi)核級緩沖區(qū)大小.
4) BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject,ULONG Filter) 為接收到的數(shù)據(jù)報設(shè)置硬件過濾規(guī)則.一般而言,需要將其設(shè)置為 NDIS_PACKET_TYPE_PROMISCUOUS(混雜模式),即接收所有流過的數(shù)據(jù)報文.
5) LPPACKET PacketAllocatePacket(void) 如果運行成功,返回一個_PACKET結(jié)構(gòu)的指針,否則返回NULL.成功返回的結(jié)果將會傳送到PacketReceivePacket()函數(shù),接收來自驅(qū)動的網(wǎng)絡(luò)數(shù)據(jù)報.
6) VOID PacketInitPacket(LPPACKET lpPacket, PVOID Buffer, UINT Length) 初始化一個_PACKET結(jié)構(gòu).
7) BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET lpPacket, BOOLEAN Sync) 發(fā)送一個或多個數(shù)據(jù)報的副本.
8) BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync) 從NPF驅(qū)動程序讀取網(wǎng)絡(luò)數(shù)據(jù)報及統(tǒng)計信息.
9) VOID PacketFreePacket(LPPACKET lpPacket) 釋放參數(shù)提供的_PACKET結(jié)構(gòu).
10) VOID PacketCloseAdapter(LPADAPTER lpAdapter) 關(guān)閉參數(shù)中提供的網(wǎng)絡(luò)適配器,釋放相關(guān)的ADAPTER結(jié)構(gòu).
5 在Windows平臺下協(xié)議棧發(fā)送和接收函數(shù)的設(shè)計
了解配置雙協(xié)議棧的問題之前,我們還要清楚:在Windows平臺下通過WinPcap可以直接對網(wǎng)絡(luò)適配器進行操作,從而實現(xiàn)發(fā)送和接收數(shù)據(jù)報文的目的.在使用WinpCap前首先需要進行初始化 操作,其步驟如下:調(diào)用PacketGetAdapterNames()獲取當(dāng)前網(wǎng)絡(luò)適配器的名稱,再調(diào)用PacketOpenAdapter()函數(shù)打 開一個網(wǎng)絡(luò)適配器,然后還需要調(diào)用PacketSetHwFilter()函數(shù)設(shè)置網(wǎng)絡(luò)適配器的過濾規(guī)則和調(diào)用PacketSetBuff()設(shè)置捕獲數(shù) 據(jù)報的內(nèi)核級緩沖區(qū)大小.
當(dāng)協(xié)議棧需要發(fā)送數(shù)據(jù)報文時,首先需要調(diào)用PacketAllocatePacket()函數(shù)為發(fā)送數(shù)據(jù)報文創(chuàng)建一個網(wǎng)絡(luò)數(shù)據(jù)報結(jié)構(gòu),然后調(diào)用 PacketInitPacket()函數(shù)對該結(jié)構(gòu)進行初始化,將存儲待發(fā)送數(shù)據(jù)報文的緩沖區(qū)指針和長度填入網(wǎng)絡(luò)數(shù)據(jù)報結(jié)構(gòu),再接下來便是調(diào)用 PacketSendPacket()函數(shù)將數(shù)據(jù)報文從指定的網(wǎng)絡(luò)適配器中發(fā)送出去,之后需要調(diào)用PacketFreePacket()函數(shù)釋放掉剛才申 請的網(wǎng)絡(luò)數(shù)據(jù)報文結(jié)構(gòu)的內(nèi)存空間.這樣,一個TCP/IP協(xié)議棧就能夠完成將一個數(shù)據(jù)報文通過WinPcap操作網(wǎng)絡(luò)適配器發(fā)送到網(wǎng)絡(luò)上的工作.
#p#
使用WinPcap接收網(wǎng)絡(luò)適配器上收集到的網(wǎng)絡(luò)上的數(shù)據(jù)報文,首先需要創(chuàng)建一個高優(yōu)先級別的任務(wù)或者線程,一般在TCP/IP協(xié) 議棧的網(wǎng)絡(luò)接口層初始化時即需要創(chuàng)建一個這樣的任務(wù)或者線程,然后在該任務(wù)或者線程函數(shù)里調(diào)用PacketAllocatePacket()為接收數(shù)據(jù)報 文創(chuàng)建網(wǎng)絡(luò)數(shù)據(jù)報結(jié)構(gòu),再調(diào)用PacketInitPacket()函數(shù)為接收的數(shù)據(jù)報文分配內(nèi)存緩沖區(qū),這個緩沖區(qū)需要盡量大一點兒,否則一旦網(wǎng)絡(luò)上數(shù) 據(jù)報文比較多,而協(xié)議棧上層來不及處理,則會造成數(shù)據(jù)報文的丟失.接下來便是循環(huán)的調(diào)用PacketReceivePacket()函數(shù)從指定的網(wǎng)絡(luò)適配 器讀取數(shù)據(jù)報文,并將數(shù)據(jù)報文拷貝到協(xié)議棧的內(nèi)存空間,再通過操作系統(tǒng)提供的任務(wù)或線程間通信的機制將該數(shù)據(jù)報文發(fā)送到TCP/IP協(xié)議棧的接收任務(wù)或者線程進行報文的分析和處理.這個數(shù)據(jù)接收的任務(wù)和線程將永遠不會返回,始終循環(huán)調(diào)用PacketReceivePacket()函數(shù)讀取網(wǎng)絡(luò)適配器上接收到的網(wǎng)絡(luò)上傳輸過來的數(shù)據(jù)報文并將其交付給TCP/IP協(xié)議棧進行處理.
6 在Windows平臺上配置雙協(xié)議棧的問題
由于Windows平臺本身自帶有TCP/IP協(xié)議棧,而我們又需要在Windows平臺上運行一個嵌入式TCP/IP協(xié)議棧,實際上是在Windows這一個操作系統(tǒng)上配置了雙TCP/IP協(xié)議棧.
要使這兩個TCP/IP協(xié)議棧相互之間互不影響并能各自良好的運行,首先需要為兩個協(xié)議棧各自分配不同的IP地址;其次在嵌入式TCP/IP協(xié)議棧中的數(shù)據(jù)鏈路層的Mac地址,一定不能使用Windows平臺的TCP/IP協(xié)議棧使用的網(wǎng)絡(luò)適配器的地址,除非計算機裝有兩塊網(wǎng)絡(luò)適配器,Windows平臺的TCP/IP協(xié)議棧使用一個網(wǎng)絡(luò)適配器進行數(shù)據(jù)的收發(fā),而嵌入式TCP/IP協(xié)議棧使用另一個網(wǎng)網(wǎng)絡(luò)適配器收發(fā)數(shù)據(jù)報文.其實在嵌入式TCP/IP協(xié) 議棧中,其鏈路層的Mac地址可以通過修改程序代碼設(shè)置任意的虛擬Mac地址,但這必須首先調(diào)用WinPcap的PacketSetHwFilter() 函數(shù)設(shè)置網(wǎng)絡(luò)適配器的接收模式為NDIS_PACKET_TYPE_PROMISCUOUS(混雜模式)用于指定網(wǎng)羅適配器接收所有流過的數(shù)據(jù)報文,否 則,網(wǎng)絡(luò)適配器會根據(jù)本身的Mac地址對網(wǎng)絡(luò)上接收到的數(shù)據(jù)報文進行Mac過濾,丟棄掉不屬于該網(wǎng)絡(luò)適配器接收的數(shù)據(jù)報文.
7 小結(jié)
作者在工作中按照上述方法,成功的在Windows平臺上運行并調(diào)試了Linux的TCP/IP協(xié)議棧,并最終將其移植到VxWorks操作系統(tǒng)中運行.在調(diào)試過程中,作者明顯感覺Windows的VC6開發(fā)平臺下調(diào)試確實比直接使用Tornado調(diào)試要方便和快捷許多.由于前期在Windows平臺上調(diào)試時解決了大部分移植和修改TCP/IP協(xié)議棧的問題,后期在Tornado下調(diào)試時基本上沒有花費太多的時間,大大提高了工作的效率,減小了開發(fā)的周期.