這是一篇關(guān)于進(jìn)程間通信的文章
轉(zhuǎn)載整理至 http://www.cnblogs.com/wcadaydayup/p/4261745.html
進(jìn)程間的通信方式:
管道(pipe)及有名管道(named pipe):
管道可用于具有親緣關(guān)系進(jìn)程間的通信,有名管道除了具有管道所具有的功能外,它還允許無(wú)親緣關(guān)系進(jìn)程間的通信涯呻。
信號(hào)(signal):
信號(hào)是在軟件層次上對(duì)中斷機(jī)制的一種模擬,它是比較復(fù)雜的通信方式贝淤,用于通知進(jìn)程有某事件發(fā)生,一個(gè)進(jìn)程收到一個(gè)信號(hào)與處理器收到一個(gè)中斷請(qǐng)求效果上可以說(shuō)是一致得政供。
消息隊(duì)列(message queue):
消息隊(duì)列是消息的鏈接表播聪,它克服了上兩種通信方式中信號(hào)量有限的缺點(diǎn),具有寫權(quán)限得進(jìn)程可以按照一定得規(guī)則向消息隊(duì)列中添加新信息布隔;對(duì)消息隊(duì)列有讀權(quán)限得進(jìn)程則可以從消息隊(duì)列中讀取信息犬耻。
消息緩沖通信技術(shù)是由Hansen首先提出的,其基本思想是:根據(jù)”生產(chǎn)者-消費(fèi)者”原理,利用內(nèi)存中公用消息緩沖區(qū)實(shí)現(xiàn)進(jìn)程之間的信息交換.
內(nèi)存中開辟了若干消息緩沖區(qū),用以存放消息.每當(dāng)一個(gè)進(jìn)程向另一個(gè)進(jìn)程發(fā)送消息時(shí),便申請(qǐng)一個(gè)消息緩沖區(qū),并把已準(zhǔn)備好的消息送到緩沖區(qū),然后把該消息緩沖區(qū)插入到接收進(jìn)程的消息隊(duì)列中,最后通知接收進(jìn)程.接收進(jìn)程收到發(fā)送里程發(fā)來(lái)的通知后,從本進(jìn)程的消息隊(duì)列中摘下一消息緩沖區(qū),取出所需的信息,然后把消息緩沖區(qū)不定期給系統(tǒng).系統(tǒng)負(fù)責(zé)管理公用消息緩沖區(qū)以及消息的傳遞.
一個(gè)進(jìn)程可以給若干個(gè)進(jìn)程發(fā)送消息,反之,一個(gè)進(jìn)程可以接收不同進(jìn)程發(fā)來(lái)的消息.顯然,進(jìn)程中關(guān)于消息隊(duì)列的操作是臨界區(qū).當(dāng)發(fā)送進(jìn)程正往接收進(jìn)程的消息隊(duì)列中添加一條消息時(shí),接收進(jìn)程不能同時(shí)從該消息隊(duì)列中到出消息:反之也一樣.
消息緩沖區(qū)通信機(jī)制包含以下列內(nèi)容:
(1) 消息緩沖區(qū),這是一個(gè)由以下幾項(xiàng)組成的數(shù)據(jù)結(jié)構(gòu):
1、 消息長(zhǎng)度
2执泰、 消息正文
3、 發(fā)送者
4渡蜻、 消息隊(duì)列指針
(2)消息隊(duì)列首指針m-q,一般保存在PCB中术吝。
(1) 互斥信號(hào)量m-mutex,初值為1,用于互斥訪問(wèn)消息隊(duì)列茸苇,在PCB中設(shè)置排苍。
(2) 同步信號(hào)量m-syn,初值為0,用于消息計(jì)數(shù)学密,在PCB中設(shè)置淘衙。
(3) 發(fā)送消息原語(yǔ)send
(4) 接收消息原語(yǔ)receive(a)
共享內(nèi)存(shared memory):
可以說(shuō)這是最有用的進(jìn)程間通信方式。它使得多個(gè)進(jìn)程可以訪問(wèn)同一塊內(nèi)存空間腻暮,不同進(jìn)程可以及時(shí)看到對(duì)方進(jìn)程中對(duì)共享內(nèi)存中數(shù)據(jù)得更新彤守。這種方式需要依靠某種同步操作,如互斥鎖和信號(hào)量等哭靖。
這種通信模式需要解決兩個(gè)問(wèn)題:第一個(gè)問(wèn)題是怎樣提供共享內(nèi)存具垫;第二個(gè)是公共內(nèi)存的互斥關(guān)系則是程序開發(fā)人員的責(zé)任。
信號(hào)量(semaphore):
主要作為進(jìn)程之間及同一種進(jìn)程的不同線程之間得同步和互斥手段试幽。
套接字(socket)筝蚕;
這是一種更為一般得進(jìn)程間通信機(jī)制,它可用于網(wǎng)絡(luò)中不同機(jī)器之間的進(jìn)程間通信,應(yīng)用非常廣泛起宽。
WINDOWS上的進(jìn)程與進(jìn)程通信
進(jìn)程是裝入內(nèi)存并準(zhǔn)備執(zhí)行的程序洲胖,每個(gè)進(jìn)程都有私有的虛擬地址空間,由代碼坯沪、數(shù)據(jù)以及它可利用的系統(tǒng)資源(如文件绿映、管道等)組成。多進(jìn)程/多線程是Windows操作系統(tǒng)的一個(gè)基本特征屏箍。Microsoft Win32應(yīng)用編程接口(Application Programming Interface, API)提供了大量支持應(yīng)用程序間數(shù)據(jù)共享和交換的機(jī)制绘梦,這些機(jī)制行使的活動(dòng)稱為進(jìn)程間通信(InterProcess Communication, IPC),進(jìn)程通信就是指不同進(jìn)程間進(jìn)行數(shù)據(jù)共享和數(shù)據(jù)交換赴魁。
正因?yàn)槭褂肳in32 API進(jìn)行進(jìn)程通信方式有多種卸奉,如何選擇恰當(dāng)?shù)耐ㄐ欧绞骄统蔀閼?yīng)用開發(fā)中的一個(gè)重要問(wèn)題,下面本文將對(duì)Win32中進(jìn)程通信的幾種方法加以分析和比較颖御。
文件映射
文件映射(Memory-Mapped Files)能使進(jìn)程把文件內(nèi)容當(dāng)作進(jìn)程地址區(qū)間一塊內(nèi)存那樣來(lái)對(duì)待榄棵。因此,進(jìn)程不必使用文件I/O操作潘拱,只需簡(jiǎn)單的指針操作就可讀取和修改文件的內(nèi)容疹鳄。
Win32 API允許多個(gè)進(jìn)程訪問(wèn)同一文件映射對(duì)象,各個(gè)進(jìn)程在它自己的地址空間里接收內(nèi)存的指針芦岂。通過(guò)使用這些指針瘪弓,不同進(jìn)程就可以讀或修改文件的內(nèi)容,實(shí)現(xiàn)了對(duì)文件中數(shù)據(jù)的共享禽最。
應(yīng)用程序有三種方法來(lái)使多個(gè)進(jìn)程共享一個(gè)文件映射對(duì)象腺怯。
- (1)繼承:第一個(gè)進(jìn)程建立文件映射對(duì)象,它的子進(jìn)程繼承該對(duì)象的句柄川无。
- (2)命名文件映射:第一個(gè)進(jìn)程在建立文件映射對(duì)象時(shí)可以給該對(duì)象指定一個(gè)名字(可與文件名不同)呛占。第二個(gè)進(jìn)程可通過(guò)這個(gè)名字打開此文件映射對(duì)象。另外懦趋,第一個(gè)進(jìn)程也可以通過(guò)一些其它IPC機(jī)制(有名管道晾虑、郵件槽等)把名字傳給第二個(gè)進(jìn)程。
- (3)句柄復(fù)制:第一個(gè)進(jìn)程建立文件映射對(duì)象仅叫,然后通過(guò)其它IPC機(jī)制(有名管道帜篇、郵件槽等)把對(duì)象句柄傳遞給第二個(gè)進(jìn)程。第二個(gè)進(jìn)程復(fù)制該句柄就取得對(duì)該文件映射對(duì)象的訪問(wèn)權(quán)限诫咱。
文件映射是在多個(gè)進(jìn)程間共享數(shù)據(jù)的非常有效方法坠狡,有較好的安全性。但文件映射只能用于本地機(jī)器的進(jìn)程之間遂跟,不能用于網(wǎng)絡(luò)中逃沿,而開發(fā)者還必須控制進(jìn)程間的同步婴渡。
共享內(nèi)存
Win32 API中共享內(nèi)存(Shared Memory)實(shí)際就是文件映射的一種特殊情況。進(jìn)程在創(chuàng)建文件映射對(duì)象時(shí)用0xFFFFFFFF來(lái)代替文件句柄(HANDLE)凯亮,就表示了對(duì)應(yīng)的文件映射對(duì)象是從操作系統(tǒng)頁(yè)面文件訪問(wèn)內(nèi)存边臼,其它進(jìn)程打開該文件映射對(duì)象就可以訪問(wèn)該內(nèi)存塊。由于共享內(nèi)存是用文件映射實(shí)現(xiàn)的假消,所以它也有較好的安全性柠并,也只能運(yùn)行于同一計(jì)算機(jī)上的進(jìn)程之間。
匿名管道
管道(Pipe)是一種具有兩個(gè)端點(diǎn)的通信通道:有一端句柄的進(jìn)程可以和有另一端句柄的進(jìn)程通信富拗。管道可以是單向-一端是只讀的臼予,另一端點(diǎn)是只寫的;也可以是雙向的-管道的兩端點(diǎn)既可讀也可寫啃沪。
匿名管道(Anonymous Pipe)是 在父進(jìn)程和子進(jìn)程之間粘拾,或同一父進(jìn)程的兩個(gè)子進(jìn)程之間傳輸數(shù)據(jù)的無(wú)名字的單向管道。通常由父進(jìn)程創(chuàng)建管道创千,然后由要通信的子進(jìn)程繼承通道的讀端點(diǎn)句柄或?qū)?端點(diǎn)句柄缰雇,然后實(shí)現(xiàn)通信。父進(jìn)程還可以建立兩個(gè)或更多個(gè)繼承匿名管道讀和寫句柄的子進(jìn)程追驴。這些子進(jìn)程可以使用管道直接通信械哟,不需要通過(guò)父進(jìn)程。
匿名管道是單機(jī)上實(shí)現(xiàn)子進(jìn)程標(biāo)準(zhǔn)I/O重定向的有效方法殿雪,它不能在網(wǎng)上使用暇咆,也不能用于兩個(gè)不相關(guān)的進(jìn)程之間。
命名管道
命名管道(Named Pipe)是服務(wù)器進(jìn)程和一個(gè)或多個(gè)客戶進(jìn)程之間通信的單向或雙向管道丙曙。不同于匿名管道的是命名管道可以在不相關(guān)的進(jìn)程之間和不同計(jì)算機(jī)之間使用爸业,服務(wù)器建立命名管道時(shí)給它指定一個(gè)名字,任何進(jìn)程都可以通過(guò)該名字打開管道的另一端河泳,根據(jù)給定的權(quán)限和服務(wù)器進(jìn)程通信。
命名管道提供了相對(duì)簡(jiǎn)單的編程接口年栓,使通過(guò)網(wǎng)絡(luò)傳輸數(shù)據(jù)并不比同一計(jì)算機(jī)上兩進(jìn)程之間通信更困難拆挥,不過(guò)如果要同時(shí)和多個(gè)進(jìn)程通信它就力不從心了。
郵件槽
郵件槽(Mailslots)提供進(jìn)程間單向通信能力某抓,任何進(jìn)程都能建立郵件槽成為郵件槽服務(wù)器纸兔。其它進(jìn)程,稱為郵件槽客戶否副,可以通過(guò)郵件槽的名字給郵件槽服務(wù)器進(jìn)程發(fā)送消息汉矿。進(jìn)來(lái)的消 息一直放在郵件槽中,直到服務(wù)器進(jìn)程讀取它為止备禀。一個(gè)進(jìn)程既可以是郵件槽服務(wù)器也可以是郵件槽客戶洲拇,因此可建立多個(gè)郵件槽實(shí)現(xiàn)進(jìn)程間的雙向通信奈揍。
通過(guò)郵件槽可以給本地計(jì)算機(jī)上的郵件槽、其它計(jì)算機(jī)上的郵件槽或指定網(wǎng)絡(luò)區(qū)域中所有計(jì)算機(jī)上有同樣名字的郵件槽發(fā)送消息赋续。廣播通信的消息長(zhǎng)度不能超過(guò)400字節(jié)男翰,非廣播消息的長(zhǎng)度則受郵件槽服務(wù)器指定的最大消息長(zhǎng)度的限制。
郵件槽與命名管道相似纽乱,不過(guò)它傳輸數(shù)據(jù)是通過(guò)不可靠的數(shù)據(jù)報(bào)(如TCP/IP協(xié)議中的UDP包)完成的蛾绎,一旦網(wǎng)絡(luò)發(fā)生錯(cuò)誤則無(wú)法保證消息正確地接收,而命名管道傳輸數(shù)據(jù)則是建立在可靠連接基礎(chǔ)上的鸦列。不過(guò)郵件槽有簡(jiǎn)化的編程接口和給指定網(wǎng)絡(luò)區(qū)域內(nèi)的所有計(jì)算機(jī)廣播消息的能力租冠,所以郵件槽不失為應(yīng)用程序發(fā)送和接收消息的另一種選擇。
剪貼板
剪貼板(Clipped Board)實(shí)質(zhì)是Win32 API中一組用來(lái)傳輸數(shù)據(jù)的函數(shù)和消息薯嗤,為Windows應(yīng)用程序之間進(jìn)行數(shù)據(jù)共享提供了一個(gè)中介顽爹,Windows已建立的剪切(復(fù)制)-粘貼的機(jī)制為不同應(yīng)用程序之間共享不同格式數(shù)據(jù)提供了一條捷徑。當(dāng)用戶在應(yīng)用程序中執(zhí)行剪切或復(fù)制操作時(shí)应民,應(yīng)用程序把選取的數(shù)據(jù)用一種或多種格式放在剪貼板上话原。然后任何其它應(yīng)用程序都可以從剪貼板上拾取數(shù)據(jù),從給定格式中選擇適合自己的格式诲锹。
剪貼板是一個(gè)非常松散的交換媒介繁仁,可以支持任何數(shù)據(jù)格式,每一格式由一無(wú)符號(hào)整數(shù)標(biāo)識(shí)归园,對(duì)標(biāo)準(zhǔn)(預(yù)定義)剪貼板格式黄虱,該值是Win32 API定義的常量;對(duì)非標(biāo)準(zhǔn)格式可以使用Register Clipboard Format函數(shù)注冊(cè)為新的剪貼板格式庸诱。利用剪貼板進(jìn)行交換的數(shù)據(jù)只需在數(shù)據(jù)格式上一致或都可以轉(zhuǎn)化為某種格式就行捻浦。但剪貼板只能在基于Windows的程序中使用,不能在網(wǎng)絡(luò)上使用桥爽。
動(dòng)態(tài)數(shù)據(jù)交換
動(dòng)態(tài)數(shù)據(jù)交換(DDE)是使用共享內(nèi)存在應(yīng)用程序之間進(jìn)行數(shù)據(jù)交換的一種進(jìn)程間通信形式朱灿。應(yīng)用程序可以使用DDE進(jìn)行一次性數(shù)據(jù)傳輸,也可以當(dāng)出現(xiàn)新數(shù)據(jù)時(shí)钠四,通過(guò)發(fā)送更新值在應(yīng)用程序間動(dòng)態(tài)交換數(shù)據(jù)盗扒。
DDE和剪貼板一樣既支持標(biāo)準(zhǔn)數(shù)據(jù)格式(如文本、位圖等)缀去,又可以支持自己定義的數(shù)據(jù)格式侣灶。但它們的數(shù)據(jù)傳輸機(jī)制卻不同,一個(gè)明顯區(qū)別是剪貼板操作幾乎總是用作對(duì)用戶指定操作的一次性應(yīng)答-如從菜單中選擇Paste命令缕碎。盡管DDE也可以由用戶啟動(dòng)褥影,但它繼續(xù)發(fā)揮作用一般不必用戶進(jìn)一步干預(yù)。DDE有三種數(shù)據(jù)交換方式:
- (1) 冷鏈:數(shù)據(jù)交換是一次性數(shù)據(jù)傳輸咏雌,與剪貼板相同凡怎。
- (2) 溫鏈:當(dāng)數(shù)據(jù)交換時(shí)服務(wù)器通知客戶校焦,然后客戶必須請(qǐng)求新的數(shù)據(jù)。
- (3) 熱鏈:當(dāng)數(shù)據(jù)交換時(shí)服務(wù)器自動(dòng)給客戶發(fā)送數(shù)據(jù)栅贴。
DDE交換可以發(fā)生在單機(jī)或網(wǎng)絡(luò)中不同計(jì)算機(jī)的應(yīng)用程序之間斟湃。開發(fā)者還可以定義定制的DDE數(shù)據(jù)格式進(jìn)行應(yīng)用程序之間特別目的IPC,它們有更緊密耦合的通信要求檐薯。大多數(shù)基于Windows的應(yīng)用程序都支持DDE凝赛。
對(duì)象連接與嵌入
應(yīng)用程序利用對(duì)象連接與嵌入(OLE)技術(shù)管理復(fù)合文檔(由多種數(shù)據(jù)格式組成的文檔),OLE提供使某應(yīng)用程序更容易調(diào)用其它應(yīng)用程序進(jìn)行數(shù)據(jù)編輯的服務(wù)坛缕。例如墓猎,OLE支持的字處理器可以嵌套電子表格,當(dāng)用戶要編輯電子表格時(shí)OLE庫(kù)可自動(dòng)啟動(dòng)電子表格編輯器赚楚。當(dāng)用戶退出電子表格編輯器時(shí)毙沾,該表格已在原始字處理器文檔中得到更新。在這里電子表格編輯器變成了字處理器的擴(kuò)展宠页,而如果使用DDE左胞,用戶要顯式地啟動(dòng)電子表格編輯器。
同DDE技術(shù)相同举户,大多數(shù)基于Windows的應(yīng)用程序都支持OLE技術(shù)烤宙。
動(dòng)態(tài)連接庫(kù)
Win32動(dòng)態(tài)連接庫(kù)(DLL)中的全局?jǐn)?shù)據(jù)可以被調(diào)用DLL的所有進(jìn)程共享,這就又給進(jìn)程間通信開辟了一條新的途徑俭嘁,當(dāng)然訪問(wèn)時(shí)要注意同步問(wèn)題躺枕。
雖然可以通過(guò)DLL進(jìn)行進(jìn)程間數(shù)據(jù)共享,但從數(shù)據(jù)安全的角度考慮供填,我們并不提倡這種方法拐云,使用帶有訪問(wèn)權(quán)限控制的共享內(nèi)存的方法更好一些。
遠(yuǎn)程過(guò)程調(diào)用
Win32 API提供的遠(yuǎn)程過(guò)程調(diào)用(RPC)使應(yīng)用程序可以使用遠(yuǎn)程調(diào)用函數(shù)近她,這使在網(wǎng)絡(luò)上用RPC進(jìn)行進(jìn)程通信就像函數(shù)調(diào)用那樣簡(jiǎn)單叉瘩。RPC既可以在單機(jī)不同進(jìn)程間使用也可以在網(wǎng)絡(luò)中使用。
由于Win32 API提供的RPC服從OSF-DCE(Open Software Foundation Distributed Computing Environment)標(biāo)準(zhǔn)粘捎。所以通過(guò)Win32 API編寫的RPC應(yīng)用程序能與其它操作系統(tǒng)上支持DEC的RPC應(yīng)用程序通信薇缅。使用RPC開發(fā)者可以建立高性能、緊密耦合的分布式應(yīng)用程序晌端。
NetBios函數(shù)
Win32 API提供NetBios函數(shù)用于處理低級(jí)網(wǎng)絡(luò)控制捅暴,這主要是為IBM NetBios系統(tǒng)編寫與Windows的接口恬砂。除非那些有特殊低級(jí)網(wǎng)絡(luò)功能要求的應(yīng)用程序咧纠,其它應(yīng)用程序最好不要使用NetBios函數(shù)來(lái)進(jìn)行進(jìn)程間通信。
Sockets
Windows Sockets規(guī)范是以U.C.Berkeley大學(xué)BSD UNIX中流行的Socket接口為范例定義的一套Windows下的網(wǎng)絡(luò)編程接口泻骤。除了Berkeley Socket原有的庫(kù)函數(shù)以外漆羔,還擴(kuò)展了一組針對(duì)Windows的函數(shù)梧奢,使程序員可以充分利用Windows的消息機(jī)制進(jìn)行編程。
現(xiàn)在通過(guò)Sockets實(shí)現(xiàn)進(jìn)程通信的網(wǎng)絡(luò)應(yīng)用越來(lái)越多演痒,這主要的原因是Sockets的跨平臺(tái)性要比其它IPC機(jī)制好得多亲轨,另外WinSock 2.0不僅支持TCP/IP協(xié)議,而且還支持其它協(xié)議(如IPX)鸟顺。Sockets的唯一缺點(diǎn)是它支持的是底層通信操作惦蚊,這使得在單機(jī)的進(jìn)程間進(jìn)行簡(jiǎn)單數(shù)據(jù)傳遞不太方便,這時(shí)使用下面將介紹的WM_COPYDATA消息將更合適些讯嫂。
WM_COPYDATA消息
WM_COPYDATA是一種非常強(qiáng)大卻鮮為人知的消息蹦锋。當(dāng)一個(gè)應(yīng)用向另一個(gè)應(yīng)用傳送數(shù)據(jù)時(shí),發(fā)送方只需使用調(diào)用SendMessage函數(shù)欧芽,參數(shù)是目的窗口的句柄莉掂、傳遞數(shù)據(jù)的起始地址、WM_COPYDATA消息千扔。接收方只需像處理其它消息那樣處理WM_COPY DATA消息憎妙,這樣收發(fā)雙方就實(shí)現(xiàn)了數(shù)據(jù)共享。
WM_COPYDATA是一種非常簡(jiǎn)單的方法曲楚,它在底層實(shí)際上是通過(guò)文件映射來(lái)實(shí)現(xiàn)的厘唾。它的缺點(diǎn)是靈活性不高,并且它只能用于Windows平臺(tái)的單機(jī)環(huán)境下洞渤。
結(jié)束語(yǔ)
Win32 API為應(yīng)用程序?qū)崿F(xiàn)進(jìn)程間通信提供了如此多種選擇方案阅嘶,那么開發(fā)者如何進(jìn)行選擇呢?通常在決定使用哪種IPC方法之前應(yīng)考慮以下一些問(wèn)題:
(1)應(yīng)用程序是在網(wǎng)絡(luò)環(huán)境下還是在單機(jī)環(huán)境下工作载迄。
附:
在我學(xué)windows編程的時(shí)候讯柔,對(duì)進(jìn)程間如何通信總是感覺很神秘,網(wǎng)絡(luò)上介紹的方法很多护昧,但是很少有一個(gè)系統(tǒng)的介紹魂迄,五花八門的說(shuō)法讓人總是一頭霧水,在這里惋耙,我整理一下各通信方法捣炬,梳理了一下這些方法的優(yōu)缺點(diǎn),希望能對(duì)各位看官起到拋磚引玉的作用绽榛。 非標(biāo)準(zhǔn)的進(jìn)程間通信技術(shù)有:Windows消息湿酸,內(nèi)存映射,內(nèi)存共享等等灭美。
- Windows消息實(shí)現(xiàn)進(jìn)程間通信推溃。 消息的接受進(jìn)程和發(fā)送進(jìn)程都要定義相同的消息。但是届腐,如果發(fā)送方僅僅是發(fā)送消息铁坎,那么發(fā)送方可以不實(shí)現(xiàn)消息映射蜂奸,不用定義消息響應(yīng)函數(shù)。接受方需要定義映射和相應(yīng)函數(shù)硬萍。 自定義消息的實(shí)現(xiàn)進(jìn)程間通信的缺陷是扩所,由于消息的傳遞參數(shù)是個(gè)長(zhǎng)整形 lparam, 因此朴乖,只能傳遞整形的數(shù)據(jù)祖屏,而不能傳遞字符串。有個(gè)可以的思路是买羞,傳遞字符串所在的地址赐劣,然后另一個(gè)程序通過(guò)獲得發(fā)送方的進(jìn)程句柄,用函數(shù)ReadProcessMemory與WriteProcessMemory操作發(fā)送方的內(nèi)存空間來(lái)讀取內(nèi)容哩都。
- 使用MFC定義的WM_COPYDATA消息 該消息其實(shí)與普通的自定義消息通信類似魁兼,區(qū)別是,傳送的是一個(gè)指向COPYDATASTRUCT 結(jié)構(gòu)的指針漠嵌,要傳遞的字符串就保存在這個(gè)結(jié)構(gòu)體里咐汞。這個(gè)結(jié)構(gòu)的第一個(gè)變量 dwData可以設(shè)置為0即可。 這個(gè)消息與 上面的那個(gè)思路的不同是儒鹿,獲得了結(jié)構(gòu)體的指針后化撕,接受進(jìn)程不需要其他的處理就能獲取到指針的數(shù)據(jù),就好像在同一個(gè)進(jìn)程里通信一樣. 另外注意约炎,該消息的接受有時(shí)并不能獲得所需要的長(zhǎng)度植阴,有可能只接收到了一部分。 因此圾浅,該方式只適合于傳遞是少量的數(shù)據(jù)掠手。
3.使用進(jìn)程內(nèi)存讀寫函數(shù) 基本上與方法一得后面猜想部分相同。關(guān)鍵是狸捕,要使用GlobalAlloc()或者VirtualAllocEx來(lái)分配內(nèi)存空間存放數(shù)據(jù)喷鸽。把數(shù)據(jù)寫入接收方的進(jìn)程內(nèi)存,然后接著就發(fā)消息告訴他數(shù)據(jù)的地址灸拍。由于是在發(fā)送方申請(qǐng)的內(nèi)存做祝,那么,最好等待sleep一定時(shí)間再VirtualFreeEx申請(qǐng)到得內(nèi)存鸡岗。 GlobalAlloc()或者VirtualAllocEx可以實(shí)現(xiàn)在另一個(gè)進(jìn)程的內(nèi)存空間來(lái)申請(qǐng)內(nèi)存混槐,這就為什么上面能進(jìn)行的原因。也就是說(shuō)轩性,發(fā)送方并不在自己的內(nèi)存空間申請(qǐng)內(nèi)存声登,而是在接收方進(jìn)程內(nèi)存空間來(lái)申請(qǐng)內(nèi)存。然后寫入輸入數(shù)據(jù)。當(dāng)然捌刮,也可以在發(fā)送方的進(jìn)程空間來(lái)申請(qǐng)內(nèi)存,接收方通過(guò)跨進(jìn)程讀寫的方式來(lái)讀舒岸。這只是處理方式不同而已绅作。
4.使用內(nèi)存映射文件的方法 內(nèi)存映射的好處就是,可以像對(duì)待一個(gè)文件一樣來(lái)對(duì)待一塊內(nèi)存區(qū)蛾派。文件時(shí)可以被不同的進(jìn)程來(lái)讀寫的俄认。既然那塊內(nèi)存 區(qū)像文件一樣,那么這塊內(nèi)存區(qū)就可以被不同的進(jìn)程來(lái)讀寫洪乍。
5.使用DLL進(jìn)行通信 Win32 DLL 只能共享代碼不能共享數(shù)據(jù)眯杏,不同的進(jìn)程載入同一個(gè)DLL文件,DLL的代碼都只載入了一份到內(nèi)存壳澳,這只載入一份代碼僅指同一個(gè)DLL文件岂贩,如果相同的DLL文件在不同的盤符下,也不是同一個(gè)DLL巷波,而是同一DLL多個(gè)副本萎津。 Win16 DLL 被載入了系統(tǒng)內(nèi)存,所以調(diào)用它的進(jìn)程都可以訪問(wèn)到它的全局變量抹镊,因此可以很容易的實(shí)現(xiàn)進(jìn)程間通信锉屈。但是對(duì)于win32 DLL , 操作系統(tǒng)會(huì)把該DLL映射到每個(gè)調(diào)用它的進(jìn)程的地址空間,DLL成為該進(jìn)程的一部分垮耳。 可以用下面的方法來(lái)將DLL的數(shù)據(jù)區(qū)設(shè)置為共享區(qū)颈渊。
#pragma data_seg("SHARED") // 定義名為SHARED的共享數(shù)據(jù)段
char m_strString[256]=TEXT(""); // 共享的數(shù)據(jù)。特別要注意需要初始化终佛,因?yàn)榫幾g器會(huì)把未初始化的變量保存在bss數(shù)據(jù)段俊嗽。
volatile bool bInCriticalSection=FALSE; // 同步標(biāo)示
#pragma data_seg()
#pragma comment(linker,"/SECTION:SHARED,RWS") // 將要共享的數(shù)據(jù)段通知編譯器。
CCriticalSection cs; // 臨界區(qū)铃彰,控制同步的 上面控制了同步問(wèn)題乌询。
- 6.使用操作系統(tǒng)提供的剪貼板實(shí)現(xiàn)通信 使用剪貼板是一中開銷較小的進(jìn)程通信機(jī)制。剪貼板機(jī)制的原理是豌研,剪貼板是系統(tǒng)預(yù)留的一塊全局內(nèi)存妹田,用來(lái)暫存進(jìn)程間進(jìn)行數(shù)據(jù)交換的數(shù)據(jù)。 提供數(shù)據(jù)的進(jìn)程需要先創(chuàng)建一個(gè)全局內(nèi)存塊鹃共,然后將要傳送的數(shù)據(jù)移到或復(fù)制到該內(nèi)存塊鬼佣。 接收進(jìn)程需要獲得此內(nèi)存塊的句柄,完成數(shù)據(jù)讀取霜浴。
下面的程序標(biāo)明怎么在剪貼板寫數(shù)據(jù)
CString strData=m_strClipBoard; // 獲得數(shù)據(jù).
// 打開系統(tǒng)剪貼板.
if (!OpenClipboard()) return;
// 使用之前晶衷,清空系統(tǒng)剪貼板.
EmptyClipboard();
// 分配一內(nèi)存,大小等于要拷貝的字符串的大小,返回該內(nèi)存控制句柄.
HGLOBAL hClipboardData;
hClipboardData = GlobalAlloc(GMEM_DDESHARE, strData.GetLength()+1);
// 內(nèi)存控制句柄加鎖晌纫,返回值為指向那內(nèi)存控制句柄所在的特定數(shù)據(jù)格式的指針.
char * pchData; pchData = (char*)GlobalLock(hClipboardData);
// 將本地變量的值賦給全局內(nèi)存.
strcpy(pchData, LPCSTR(strData));
// 給加鎖的全局內(nèi)存控制句柄解鎖.
GlobalUnlock(hClipboardData);
// 通過(guò)全局內(nèi)存句柄將要拷貝的數(shù)據(jù)放到剪貼板上.
SetClipboardData(CF_TEXT,hClipboardData);
// 使用完后關(guān)閉剪貼板.
CloseClipboard();
從剪貼板讀取數(shù)據(jù)的代碼如下:
// 打開系統(tǒng)剪貼板.
if (!OpenClipboard()) return;
// 判斷剪貼板上的數(shù)據(jù)是否是指定的數(shù)據(jù)格式.
if (IsClipboardFormatAvailable(CF_TEXT)|| IsClipboardFormatAvailable(CF_OEMTEXT)) {
// 從剪貼板上獲得數(shù)據(jù).
HANDLE hClipboardData = GetClipboardData(CF_TEXT);
// 通過(guò)給內(nèi)存句柄加鎖税迷,獲得指向指定格式數(shù)據(jù)的指針.
char *pchData = (char*)GlobalLock(hClipboardData);
// 本地變量獲得數(shù)據(jù).
m_strClipBoard = pchData;
// 給內(nèi)存句柄解鎖.
GlobalUnlock(hClipboardData);
}
else
{
AfxMessageBox("There is no text (ANSI) data on the Clipboard."); }
// 使用完后關(guān)閉剪貼板.
CloseClipboard();
// 更新數(shù)據(jù).
UpdateData(FALSE);
7.DDE (Dynamic Data Exchange)動(dòng)態(tài)數(shù)據(jù)交換 目前微軟已經(jīng)停止了開發(fā)這種技術(shù),僅僅保留了支持锹漱。 高級(jí)通信技術(shù) 前面都是幾種基本的進(jìn)程通信技術(shù)箭养,消息管道(Message Pipes), 郵槽(Mail slots), 和套接字(Sockets)則是實(shí)際比較常見的方法哥牍,這幾種高級(jí)通信除了可以像上面的方法樣實(shí)現(xiàn)本地系統(tǒng)進(jìn)程間的通信毕泌,也可以用于遠(yuǎn)程不同系統(tǒng)間的通信。
- 消息管道 Message Pipes又分為匿名管道(anonymous Pipes),和 命名管道(Named Pipes), 匿名管道主要用于本地系統(tǒng)上父進(jìn)程與他啟動(dòng)的子進(jìn)程間的通信嗅辣。命名管道高級(jí)些撼泛,可以再不同的系統(tǒng)上的進(jìn)程間通信,因?yàn)閁NIX, LINUX等都支持這項(xiàng)技術(shù)澡谭,因此愿题,命名管道技術(shù)是比較理想的C/S結(jié)構(gòu)通信技術(shù)。 命名管道原理是蛙奖,一個(gè)進(jìn)程把數(shù)據(jù)放進(jìn)管道中抠忘,另一個(gè)知道管道名字的經(jīng)常來(lái)把數(shù)據(jù)取走。其他不知道管道名字的進(jìn)程不可能能把數(shù)據(jù)取走外永。 因此崎脉,管道實(shí)際上就是一塊進(jìn)程間的共享內(nèi)存。 創(chuàng)建管道的進(jìn)程叫管道服務(wù)器伯顶,鏈接管道的進(jìn)程就是客戶機(jī)囚灼。創(chuàng)建管道的函數(shù)是HANDLE CreateNamedPipe(….); 連接管道 CallNamedPipe(); 讀入或?qū)懭霐?shù)據(jù)后腰關(guān)閉它 ConnectNamedPipe(); 服務(wù)器準(zhǔn)備好一個(gè)連接到客戶進(jìn)程的管道,并一直等待知道客戶連接上為止祭衩。 DisconnectNamedPipe(); 服務(wù)器中斷與客戶的連接 GetNamedPipeHandleState(); 獲取一個(gè)命名管道的狀態(tài)信息 GetNamedPipeInfo();獲取一個(gè)命名管道的信息 PeekNamedPipe(); 從一個(gè)管道中復(fù)制數(shù)據(jù)到一個(gè)緩沖區(qū) SetNamedPipeHandleState(); 設(shè)置一個(gè)管道的狀態(tài)信息以及管道類型 TransactNamedPipe(); 從一個(gè)消息管道讀消息或?qū)懴?WaitNamedPipe(); 使服務(wù)器等待來(lái)自客戶的實(shí)例連接灶体。 管道通信基本流程
(1)連接建立 服務(wù)器端通過(guò)ConnectNamedPipe函數(shù)建立以個(gè)命名管道實(shí)例,然后通過(guò)ConnectNamedPipe()函數(shù)來(lái)偵聽來(lái)自客戶端得請(qǐng)求掐暮。這個(gè)函數(shù)可以設(shè)置等待時(shí)間蝎抽。 客戶端只需使用函數(shù)WaitNamedPipe()來(lái)連接服務(wù)器。
(2)通信實(shí)現(xiàn) 建立連接后路克,就可以通過(guò)得到管道的文件句柄利用ReadFile()與WriteFile()進(jìn)行彼此間的通信樟结。
(3)連接終止 客戶端調(diào)用CloseFile(), 服務(wù)器端調(diào)用DisconnectNamedPipe()終止連接。且都需要CloseHandle來(lái)關(guān)閉管道精算。
9.郵槽通信
10.套接字通信 套接字通信過(guò)程可簡(jiǎn)單的描述為瓢宦,主要調(diào)用5個(gè)函數(shù),socket(),bind(), Listen(), connect(), accept(). 服務(wù)器端主要調(diào)用socket(),bind(), Listen(),accept()灰羽。 客戶端主要調(diào)用socket(),connect()驮履。 雙方的數(shù)據(jù)傳送就是通過(guò)send() 與recv()完成鱼辙。 套接字類型主要有5種,SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_SEQPACKET, SOCK_RDM.
10.1 Winsock 程序設(shè)計(jì)流程
(1)程序編譯環(huán)境 有兩套函數(shù)進(jìn)行Winsock程序設(shè)計(jì)玫镐,Socket1.1 與Socket2.0. 可以靈活混用倒戏。Socket2.0得功能較為強(qiáng)大。 包含其中一個(gè)頭文件及其對(duì)應(yīng)的庫(kù)文件即可恐似。
// Socket2.0
#include
#pragma comment (lib, “ws2_32.lib”);
// Socket1.1
#include
#pragma comment (lib, “wsock32.lib”);
(2)選擇機(jī)制(異步杜跷?非阻塞?) 默認(rèn)情況下都是創(chuàng)建的阻塞套接字蹂喻。可以通過(guò)select或者WSAAsynSelect()函數(shù)將其變?yōu)榉亲枞奈媸佟L貏e注意口四,用這個(gè)函數(shù)改為非阻塞后,不能簡(jiǎn)單的利用ioctlsocket()將它再變?yōu)樽枞J角芈R簿褪钦f(shuō)這兩個(gè)函數(shù)改變阻塞模式是由區(qū)別的蔓彩。ioctlsocket()是將異步模式的套接字再改回阻塞模式,但之前要調(diào)用WSAAsynSelect()取消所有的異步事件,WSAAsynSelect(s,hWnd,0,0);
(3)啟動(dòng)與終止 啟動(dòng)函數(shù)WSAStartup()建立于Winsock DLL 的連接驳概, 終止函數(shù)WSAClearup()終止該DLL赤嚼,這兩個(gè)函數(shù)必須成對(duì)使用。
(4)出錯(cuò)處理 Winsock為了與以后的多線程環(huán)境相兼容顺又,提供了兩個(gè)出錯(cuò)處理函數(shù)來(lái)獲取和設(shè)置當(dāng)前線程的最近錯(cuò)誤號(hào)更卒,即WSAGetLastError()和WSASetLastError();