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