《VC進(jìn)程間通信》word版_第1頁
《VC進(jìn)程間通信》word版_第2頁
《VC進(jìn)程間通信》word版_第3頁
《VC進(jìn)程間通信》word版_第4頁
《VC進(jìn)程間通信》word版_第5頁
已閱讀5頁,還剩13頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、.VC 進(jìn)程間通信在Windows下各個任務(wù)是以不同的進(jìn)程來完成的,當(dāng)一個進(jìn)程啟動后,操作系統(tǒng)為其分配了4GB的私有地址空間,由于位于同一個進(jìn)程中的線程共享同一個地址空間,所以線程間的通信很簡單,就像兩個人假設(shè)在同一個房間里說話的話就比較容易,只要動動嘴皮子就OK了,但是假設(shè)在兩個國家里就比較費事,必須借助于一些其他的手段,比方打 等.以下介紹四種進(jìn)程通信方式,雖然是在windows下的環(huán)境但是在其他的操作系統(tǒng)里也遵循著同樣的原理,不信的話可以把大學(xué)里的操作系統(tǒng)教材拿出來看看,它們分別是剪貼板、匿名管道、命名管道和郵槽。1.剪貼板clipboard其實這個東西我們每天操作電腦的時候都在接觸,我

2、們經(jīng)常實用ctrl+c和ctrl+v就是基于了剪貼板的方式來實現(xiàn)了兩個進(jìn)程間的通信,就拿我如今來說吧,我在寫這篇文章的時候是在notepad下寫的,一會我要把這篇文章里的所有文字都粘貼到csdn的網(wǎng)頁上,這里就是兩個進(jìn)程,一個是notepad進(jìn)程和一個IE進(jìn)程進(jìn)展通信,它們要傳輸?shù)臄?shù)據(jù)格式是TEXT,當(dāng)然你也可以把這些內(nèi)容拷貝到word、Excel、PowerPoint甚至是另一個notepad上面你要清楚再啟動一個notepad,這個跟前一個notepad是兩個進(jìn)程,雖然它們長得很像,這就說明剪貼板是所有程序都可以訪問的,假設(shè)你對多線程編程比較理解的話,你就會明白一個數(shù)據(jù)一旦要被很多線程訪問

3、,假設(shè)這些線程中有一些需要求改這個數(shù)據(jù),就要對這個數(shù)據(jù)加鎖來保證數(shù)據(jù)的正確性了,剪貼板也是一樣的,當(dāng)我把這段文字ctrl+c時,它就要先對系統(tǒng)中的剪貼板加鎖,然后把內(nèi)容放進(jìn)去,再釋放鎖,假設(shè)你明白了以上的一些道理,那么請你繼續(xù)往下看,假設(shè)還沒太明白那也請你繼續(xù)往下看,也許你對文字的理解才能已經(jīng)落后于對代碼的理解了.BOOL OpenClipboardwindows提供的一個API函數(shù),作用是翻開剪貼板,假設(shè)程序翻開了剪貼板,那么其他程序經(jīng)不能修改剪貼板道理上面講了,直到CloseClipboard,在windows中所有帶有Open這個單詞的函數(shù)都會有一個與之對應(yīng)的帶有Close這個單詞的函數(shù)

4、,而且你在open之后一定不要忘記close,你可以自己試試看,只調(diào)用OpenClipboard而不去執(zhí)行CloseClipboard會有什么效果,至今我還沒有發(fā)現(xiàn)例外的情況,假設(shè)你發(fā)現(xiàn)了請你告訴我.HANDLE SetClipboardDataUINT uFormat,HANDLE hMem它的作用是將hMem所"代表"的內(nèi)存中的內(nèi)容以uFormat的格式放到剪貼板上,詳細(xì)的參數(shù)說明去查MSDN吧,這里你可能有一些疑問,hMem是個句柄而內(nèi)存是用指針來訪問的,你說的沒錯,所以我用了"代表"這個詞而沒有用"指向",在windows里很

5、多資源都會有一個HANDLE以它來標(biāo)識各個資源一遍于操作系統(tǒng)的管理,內(nèi)存也一樣,我們一般動態(tài)開拓用new,malloc的he ap都不會被操作系統(tǒng)任意挪動,因為它是一個進(jìn)程的私有空間,而假設(shè)你開拓全局Heap數(shù)據(jù)的話,操作系統(tǒng)很可能會挪動它,假設(shè)這個時候你已然使用指針的話,那么操作系統(tǒng)一旦挪動了一塊全局Heap數(shù)據(jù)就要修改到所有指向這塊內(nèi)存的指針,這顯然不現(xiàn)實,而這個時候假設(shè)你已然使用你的指針來管理那塊內(nèi)存的話,那就出了大費事,因為那塊內(nèi)存已經(jīng)被移走了,而假設(shè)使用句柄來標(biāo)識這塊內(nèi)存的話那么會解決這個問題,因為它只是一個標(biāo)簽,并沒有實際的物理意義,就像假設(shè)你使用一個人的家庭住址來標(biāo)識這個人的話就

6、會有費事,因為一旦他搬走了,你就找錯人了,但是以身份證號就OK了,詳細(xì)的情況可以參考GlobalAlloc這個函數(shù)。BOOL IsClipboardFormatAvailableUINT uFormat這個函數(shù)的作用就是要檢查一下剪貼板中的數(shù)據(jù)是否是uFormat形式的,比方我現(xiàn)翻開了mspaint畫圖板程序畫了幾筆,然后Ctrl+C,再翻開notepad程序Ctrl+V,你當(dāng)然知道這不會成功,它就是使用了這個API函數(shù)在粘貼前判斷了一下剪貼板中的數(shù)據(jù)類型是否是我所需要的.好了我們下面來寫兩個進(jìn)程來實現(xiàn)它們的通信,事先說明我寫的只是關(guān)鍵代碼并不能直接運行發(fā)送方:void Sendchar*pS

7、ndifOpenClipboardHANDLE hClip;char*pBuf=NULL;/對一個指針變量以NULL來初始化是個很好的習(xí)慣EmptyClipboard;/清空剪貼板上的內(nèi)容hClip=GlobalAllocGMEM_MOVEABLE,strlenpSnd+1;pBuf=char*GlobalLockhClip;/得到句柄標(biāo)識的內(nèi)存的實際物理地址,lock后系統(tǒng)就不能把它亂挪動了strcpypBuf,pSnd;GlobalUnloakhClip;/跟open和close的關(guān)系是一樣的,有l(wèi)ock的也不要忘記unlock SetClipboardDataCF_TEXT,hClip;

8、CloseClipboard;/有open就不要忘記close在你的程序中參加以上這段話,它就把pSnd中的內(nèi)容發(fā)到了剪貼板上,相當(dāng)于你作了Ctrl+C,不信你可以執(zhí)行這段程序后,翻開一個notepad然后手動Ctrl+v看看是不是很驚奇.void ReceiveifOpenClipboardifIsClipboardFormatAvailableCF_TEXT/判斷剪貼板中的數(shù)據(jù)是否是文本HANDLE hClip;char*pBuf=NULL;hClip=GetClipboardDataCF_TEXT;/根據(jù)編程中的對稱原那么,這個我就不介紹了pBuf=char*GlobalLockhCli

9、p;GlobalUnlockhClip;MessageBoxpBuf;/顯示出來&nb sp;CloseClipboard;上面這段程序就相當(dāng)于你執(zhí)行了Ctrl+V操作,它把剪貼板中的數(shù)據(jù)取了出來;剪貼板是系統(tǒng)提供的,所有進(jìn)程都可以訪問它,它就是一段全局內(nèi)存區(qū),操作系統(tǒng)中的每個進(jìn)程就都會像線程訪問共享變量一樣的使用它,很簡單,但是問題很多,正是因為所有的進(jìn)程都可以訪問它,所以假設(shè)你的兩個進(jìn)程間的通信假設(shè)使用這種方式的話,第一,通信效率不高;第二,會影響到其他進(jìn)程的執(zhí)行,假設(shè)我如今Ctrl+C了一段文字,再執(zhí)行Ctrl+V的時候卻出現(xiàn)了一些亂七八糟的東西的話那就會很費事,所以可以基于剪貼

10、板來做一個簡單的病毒程序,假設(shè)你有興趣的話;2.匿名管道Pipe如今大多數(shù)都是基于管道通信的,因為每兩個進(jìn)程都可以共享一個管道來進(jìn)展單獨的對話,就象打 單獨占用一條線路一樣,而不必?fù)?dān)憂像剪貼板一樣會有串音,匿名管道是一種只能在本地機(jī)器上實現(xiàn)兩個進(jìn)程間通信的管道,它只能用來實現(xiàn)一個父進(jìn)程和一個子進(jìn)程之間實現(xiàn)數(shù)據(jù)傳輸.其實它是非常有用的,我做過一個實際的工程就是利用匿名管道,工程就是讓我寫一個Ping程序來監(jiān)測網(wǎng)絡(luò)的通信狀況,并且要把統(tǒng)計結(jié)果和執(zhí)行過程顯示在我們的軟件里,windows有一個自帶的ping程序,而且有執(zhí)行過程和統(tǒng)計,所以我沒必要再創(chuàng)造一個重復(fù)創(chuàng)造就等于犯罪-程序員要牢記阿,只是wi

11、ndows的那個Ping程序的執(zhí)行結(jié)果都顯示在了CMD的界面上了,我需要把它提取出來顯示在我們的軟件界面上,于是我就利用了匿名管道實現(xiàn)了這個程序,當(dāng)我們的軟件要啟動Ping任務(wù)時,我就先CreatePipe創(chuàng)立匿名管道,再CreateProcess啟動了windows下面的Ping程序它作為我們軟件的子進(jìn)程,當(dāng)然要把管道的讀寫句柄一起傳給子進(jìn)程,這樣我就可以輕松的把Ping的執(zhí)行結(jié)果了寫入到我的Buffer里了,是不是很easy。BOOL CreatePipePHANDLE hReadPipe,PHANDLE hWritePipe,LPSECURITY_ATTRIBUTES lpPipeAtt

12、ributes,DWORD nSize這個API函數(shù)是有用來創(chuàng)立匿名管道的,它返回管道的讀寫句柄hReadPipe,hWritePipe,記住lpPipeAttributes不能為NULL,因為這意味著函數(shù)的返回句柄不能被子進(jìn)程所繼承,你要知道匿名管道可是實現(xiàn)父子進(jìn)程通信的阿,只有當(dāng)一個子進(jìn)程從其父進(jìn)程中繼承了匿名管道句柄后,這兩個進(jìn)程才可以通信,lpPipeAttributes不為NULL還遠(yuǎn)不夠,LPSECURITY_ATTRIBUTES這個構(gòu)造體的內(nèi)容去查MSDN吧,我只告訴你其中的BOOL bInheritHandle這個成員變量要賦值為TRUE,這樣才真正實現(xiàn)了子進(jìn)程可以從父進(jìn)程中繼

13、承匿名管道.BOOL CreateProcess.這個系統(tǒng)API函數(shù)是用來在你的進(jìn)程中啟動一個子進(jìn)程用的,它的參數(shù)實在太多了,你還是去查MSDN吧,別怪我太懶惰,我只說幾個關(guān)鍵的地方,不想說的太詳細(xì).下面我就在寫一個程序利用匿名管道來通信父進(jìn)程的實現(xiàn):Class CParent.private:HANDLE m_hWrite;HANDLE m_hRead;void CParent:onCreatePipeSECURITY_ATTRIBUTES sa;/父進(jìn)程傳遞給子進(jìn)程的一些信息sa.bInheritHandle=TRUE;/還記得我上面的提醒吧,這個來允許子進(jìn)程繼承父進(jìn)程的管道句柄sa.lp

14、SecurityDescriptor=NULL;sa.nLength=sizeofSECURITY_ATTRIBUTES;if!CreatePipe&m_hRead,&m_hWrite,&sa,0return;STARTUPINFO sui;PROCESS_INFOMATION pi;/保存了所創(chuàng)立子進(jìn)程的信息ZeroMemory&sui,sizeofSTARTUPINFO;/對一個內(nèi)存區(qū)清零,最好用ZeroMemory,它的速度要快于memset sui.cb=sizeofSTARTUPINFO;sui.dwFlags=STARTF_USESTDHANDLES

15、;sui.hStdInput=m_hRead;sui.hstdOutput=m_hWrite;/×以上兩行也許大家要有些疑問,為什么把管道讀句柄m_hRead賦值給了hStdInput,因為管道是雙向的,對于父進(jìn)程寫的一端正好是子進(jìn)程讀的一端,而m_hRead就是父進(jìn)程中對管道讀的一端,自然要把這個句柄給子進(jìn)程讓它來寫數(shù)據(jù)了sui是父進(jìn)程傳給子進(jìn)程的數(shù)據(jù)構(gòu)造,里面包含了一些父進(jìn)程要告訴子進(jìn)程的一些信息,反之一樣×/sui.hStdError=GetStdHandleSTD_ERROR_HANDLE;if!CreateProcess"Child.exe",

16、NULL,NULL,NULL,TRUE,0,NULL,NULL,&sui,&piCloseHandlem_hRead;CLoseHandlem_hWrite;return;elseCloseHandlepi.hProcess;/子進(jìn)程的進(jìn)程句柄Closehandlepi.hThread;/子進(jìn)程的線程句柄,windows中進(jìn)程就是一個線程的容器,每個進(jìn)程至少有一個線程在執(zhí)行void CPraent:OnPiepReadchar buf100;DWORD dwRead;if!ReadFilehRead,buf,100,&dwRead,NULL/從管道中讀取數(shù)據(jù)/*這種讀取

17、管道的方式非常不好,最好在實際工程中不要使用,因為它是阻塞式的,假設(shè)這個時候管道中沒有數(shù)據(jù)他就會一直阻塞在那里,程序就會被掛起,而對管道來說一端正在讀的時候,另一端是無法寫的,也就是說父進(jìn)程阻塞在這里后,子進(jìn)程是無法把數(shù)據(jù)寫入到管道中的,在調(diào)用ReadFile之前最好調(diào)用PeekNamePipe來檢查管道中是否有數(shù)據(jù),它會立即返回,或者使用重疊式讀取方式,那么ReadFile的最后一個參數(shù)不能為NULL*/return;Messageboxbufvoid CParent:onPipeWritechar*pBufASSERTpBuf!=NULL;/這個很重要DWORD dwWrite;if!Wr

18、iteFilehWrite,pBuf,strlenpBuf+1,&dwWrite,NULL/向管道中寫數(shù)據(jù)return;子進(jìn)程的實現(xiàn):Class Child.private:HANDLE m_hRead;HANDLE m_hWrite;void CChild:CChildm_hRead=GetStdHandleSTD_INPUT_HANDLE;m_hWrite=GetStdhandleSTD_OUTPUT_HANDLE;/×GetStdhandle獲得標(biāo)準(zhǔn)輸入輸出句柄,假設(shè)你希望你的程序也能跟其他父進(jìn)程通信的話最好也這么作,并不是所有的程序被創(chuàng)立了后都能跟父進(jìn)程通信的,我用過

19、很多老外寫的小程序,它們都提供了標(biāo)準(zhǔn)的對外通信接口,這樣很便于你的使用特別對程序員×/void CChild:OnReadPipevoi dCChild:OnWritePipe/*這兩個函數(shù)與CParent中的一樣*/匿名管道由于是匿名的方式所以它不能實現(xiàn)兩個同級的進(jìn)程進(jìn)展通信,因為一個進(jìn)程創(chuàng)立了一個管道后,另一個線程并不知道如何找到這個管道,所以它只能通過父進(jìn)程直接把管道讀寫柄直接傳遞給子進(jìn)程的方式進(jìn)展進(jìn)程通信,至于為什么有了命名管道還要保存匿名管道的問題,我想主要是因為父子進(jìn)程通信的方式已然被廣泛的采用,而這種方式無疑要比命名管道消耗的資源更少,效率更高,就像自己自己寫的進(jìn)程調(diào)用

20、了自己寫的一個函數(shù)一樣。3.命名管道Pipe命名管道不僅可以在本機(jī)上實現(xiàn)兩個進(jìn)程間的通信,還可以跨網(wǎng)絡(luò)實現(xiàn)兩個進(jìn)程間的通信,就像我如今正使用MSN跟我遠(yuǎn)方的同學(xué)聊天一樣!其實假設(shè)你用過Socket編寫網(wǎng)絡(luò)程序的話,你就會明白所謂的命名管道之間的通信就相當(dāng)于把計算機(jī)低層網(wǎng)絡(luò)網(wǎng)絡(luò)通信部分給封裝了起來,使用戶使用起來不必理解那么多網(wǎng)絡(luò)通信的知識,總之一句話就是用起來簡單,其實我們在為別人提供函數(shù)庫的時候都應(yīng)該遵循這個規(guī)律,把低層煩瑣,復(fù)雜,抽象的都封裝起來,對高層提供統(tǒng)一的接口.在Windows2000/NT以后,都可以在創(chuàng)立管道時指定據(jù)有訪問權(quán)限的用戶使用管道,進(jìn)一步保證了平安性,而假設(shè)你要是自己

21、使用Socket實現(xiàn)這個功能的話就太費事了,當(dāng)然很多程序員已然會自己實現(xiàn)它,他們的理由很可能是因為windows都不平安.命名管道實現(xiàn)進(jìn)程間的通信也跟網(wǎng)絡(luò)通信一樣是C/S構(gòu)造的,效勞器進(jìn)程負(fù)責(zé)創(chuàng)立命名管道及承受客戶機(jī)的連接懇求,就象socket中Server部分要實現(xiàn)bind、linstening和accept一樣,而客戶端只負(fù)責(zé)連接,對應(yīng)于socket中的connect一樣.命名管道提供了兩種根本通信形式:字節(jié)形式和消息形式,在字節(jié)形式下,數(shù)據(jù)以一個連續(xù)的字節(jié)流的形式在server于client之間流動,而消息形式下,客戶機(jī)和效勞器那么通過一系列不連續(xù)的數(shù)據(jù)單位進(jìn)展數(shù)據(jù)收發(fā),每次管道上發(fā)出了

22、一條消息后,它必須作為一條完好的消息讀入,是不是很像TCP和UDP.HANDLE CreateNamePipe.創(chuàng)立命名管道的API,我仍然不想解釋它的詳細(xì)參數(shù)含義,我只解釋它的第一個參數(shù)LPCTSTR lpName,它的字符串格式是".pipepipename"為什么這么多,其實一共就4個,可你看到有8個是因為C/C+中字符串中假設(shè)包含一個''就必須""才能表達(dá)它的意思,你還記得嗎?它的實際格式是".pipepipename",它的'.'表示的是本機(jī)地址,假設(shè)是要與遠(yuǎn)程效勞器連接,就在這個'.

23、'處指定效勞器的名稱,接下來的pipe是固定的不要改,pipename就是你要命名的管道名字.BOOL ConnectNamedPipeHANDLE hNamePipe,LPOVERLAPPED lpOverlapped初看這個函數(shù)的名字你一定認(rèn)為這個是客戶端用來連接效勞器管道的,事物的外表總是欺騙我們,恰恰相反它是效勞器用來等待遠(yuǎn)程連接的,類似于socket中的listen.BOOL WaitNamedPipeLPCTSTR lpNamedPipeName,DWORD nTimeOut有了上面那個函數(shù)的教訓(xùn),假設(shè)我問題這個函數(shù)是作什么的你一定不會立即答復(fù),是的,它是在客戶端來判斷是否

24、有可以利用的命名管道的,每個客戶端最開場都應(yīng)該使用它判斷一些,就像socket中的connect要判斷一下server是否已經(jīng)啟動了.下面是效勞器代碼:class CNamePipeServer.private:HANDLE m_hPipe;/*創(chuàng)立命名管道等待客戶端連接*/void CNamePipeServer:NamePipeCreatedm_hPipe=CreateNamedPipe".pipeMyPipe",PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,0,1,1024,1024,0,NULL;ifINVALID_HANDLE_V

25、ALUE=m_hPipereturn;HANDLE hEvent;hEvent=CreateEventNULL,TRUE,FALSE,NULL;/創(chuàng)立一個事件ifINVALID_HANDLE_VALUE=hEventreturn;OVERLAPPED ovlap;ZeroMemory&ovlap,sizeofOVERLAPPED;ovlap。hEvent=hEvent;/*等待客戶連接,采用了重疊方式,該函數(shù)會立即返回不會阻塞*/if!ConnectNamePipehPipe,&ovlap/*由于函數(shù)會立即返回,所以在沒有連接的時候不會阻塞會返回,這個時候要判斷錯誤失敗的原因*

26、/ifERROR_IO_PENDING!=GetLastError.return;/*一個連接到來的時候,Event會立即變?yōu)橛行盘枲顟B(tài)*/ifWAIT_FAILED=WaitForSingleObjecthEvent,INFINTE.return;CloseHandlehEvent;void CNamePipeServer:OnReadPipevoid CNamePipeServer:OnWritePipe命名管道讀寫的方式與匿名管道的一樣,不再冗述??蛻舳藢崿F(xiàn):clase CNamePipeClient.private:HANDLE m_hPipe;void CNamePipeClient

27、:OnPipeConnectif!WaitNamedPipe".pipeMyPipe",NMPWAIT_WAIT_FOREVERreturn;/*翻開命名管道,與效勞器進(jìn)展通信,CreateFile這個函數(shù)是不是很熟悉,是的我們寫文件的時候都用這個API,其實不僅是創(chuàng)立文件,只要是句柄標(biāo)識的資源似乎都可以用它來來創(chuàng)立,如與硬件COM口之間的通信等,這就是對下層詳細(xì)實現(xiàn)封裝,對上提供統(tǒng)一接口的好處,不然不知道我們又要多記多少個API函數(shù)*/m_hPipe=CreateFile".pipeMyPipe",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL;ifINVALID_HANDLE_VALUE=m_hPipereutrn;void CNamePipeClient:OnReadPipevoid CNamePipeClient:OnWritePipe同上.命名管道我沒有在實際中使用過,所以對它的一些特點理解的并不是很透徹,不能為大家提供更多的建議了

溫馨提示

  • 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)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論