一種嵌入式RPC的設計與實(shí)現
過(guò)程調用的類(lèi)型定義如下。RPC_TYPE_SIMPLE_WRITEREAD是簡(jiǎn)單的讀寫(xiě),輸入參數和輸出參數都在頭信息和過(guò)程的參數數據結構中。RPC_TYPE_READ指返回結果保存在單獨的內存。RPC_TYPE_WRITE指寫(xiě)信息保存在單獨的內存。RPC_TYPE_WRITE_READ調用是需要內存保存輸入數據,返回時(shí)需要保存輸出的結果。

每個(gè)過(guò)程定義自己的輸入輸出參數結構。例如對獲取串口狀態(tài)GetCommState過(guò)程,建立RPC_GETCOMMSTATE結構。

由于各個(gè)編譯器對struct數據結構的成員的對齊實(shí)現不同。這樣同樣的struct在客戶(hù)端和服務(wù)器端的大小可能不同,同樣的成員在結構中的位置不同。為了確??蛻?hù)端和服務(wù)器端有相同的對齊,我們采用字節對齊用#pragma pack(1)。
3.2 Packet內存布局
開(kāi)始依次是頭信息和參數,其余部分根據特定的過(guò)程而不同。以RPC_TYPE_WRITE_READ類(lèi)型的布局為例:頭信息,參數,輸入內存塊[1…N],輸出內存塊[1…N]。其他的過(guò)程類(lèi)型布局類(lèi)似。
3.3 服務(wù)器端實(shí)現
3.3.1 網(wǎng)絡(luò )模塊實(shí)現
RPC在單獨的任務(wù)中執行。圖5為RPC任務(wù)流程圖。調用VxWorks的系統函數taskSpawn建立RPC任務(wù)。調用socket( )建立面向連接的SOCK_ STREAM套接字,bind將套接字與本地網(wǎng)絡(luò )地址和端口號捆綁,listen申明要在該端口偵聽(tīng)客戶(hù)連接請求,accept阻塞等待請求的到來(lái)。本文引用地址:http://dyxdggzs.com/article/150615.htm
3.3.2 狀態(tài)機實(shí)現
當accept后,進(jìn)入服務(wù)器端狀態(tài)機。設置accept返回的socket為非阻塞狀態(tài)。在阻塞的socket上調用send時(shí),如果沒(méi)有足夠的輸出緩沖區,該調用將被阻塞。Recv也是一樣,要讀的數據沒(méi)有就緒時(shí),調用者阻塞。服務(wù)器不知道每次要讀取的字節數,所以阻塞的socket無(wú)法工作。
分配2塊內存:A和B。內存A用來(lái)保存recv的內容,內存B用來(lái)保存客戶(hù)端發(fā)送的Packet內容。因為服務(wù)器不知道客戶(hù)會(huì )發(fā)送多大的內容過(guò)來(lái),每次從內存A拷貝到內存B之前檢查內存B的大小,如果內存B剩余大小不夠則重新分配。
在得到了整個(gè)Packet后,即GetComplatePacket后,根據dwCallID調用服務(wù)器的本地過(guò)程,待返回后將返回值和內存打包發(fā)送給客戶(hù)端。
3.4 客戶(hù)端實(shí)現
客戶(hù)端的流程如圖6所示。在Windows下運行,首先調用WSAStartup,Windows根據請求的Socket版本來(lái)搜索相應的Socket庫,然后綁定找到的Socket庫到該應用程序中。然后初始化socket,連接到服務(wù)器,接著(zhù)過(guò)程調用。比如過(guò)程調用1會(huì )進(jìn)入圖4狀態(tài)機。狀態(tài)機和服務(wù)器端類(lèi)似,只是首先參數打包,發(fā)送給服務(wù)器,返回后拆包并拷貝返回信息到內存中。
4 結束語(yǔ)
本文設計和實(shí)現的RPC可應用于白盒測試、跨平臺開(kāi)發(fā)環(huán)境和開(kāi)發(fā)客戶(hù)端軟件等。商用的嵌入式IDE軟件都很昂貴,通過(guò)本RPC,測試人員就可用開(kāi)源的環(huán)境如cygwin等開(kāi)發(fā)白盒測試代碼。另外對于有大量操作界面的嵌入式開(kāi)發(fā),需要頻繁下載到開(kāi)發(fā)板上驗證,本文RPC可應用于構建跨平臺的開(kāi)發(fā)環(huán)境,直接在Windows上開(kāi)發(fā)界面部分,最后下載到開(kāi)發(fā)板上,從而大大提高開(kāi)發(fā)效率。大多數的嵌入式軟件都有相應的PC客戶(hù)端軟件,本文的實(shí)現也適用于開(kāi)發(fā)PC客戶(hù)端軟件。
評論