c# 如何實(shí)現(xiàn)不同進(jìn)程之間的通信
進(jìn)程之間的通信是為了解決不同進(jìn)程之間的數(shù)據(jù)傳輸問(wèn)題,這樣可以讓不同程序交互數(shù)據(jù)。實(shí)現(xiàn)進(jìn)程通信的方式:1、剪切板;2、COM;3、內(nèi)存映射文件;4、WCF
1、剪切板Clipboard在進(jìn)程間傳送對(duì)象
剪切板是一個(gè)供應(yīng)用程序使用的公有區(qū)域。在.NET中定一個(gè)了一個(gè)DataFormats類,此類包含一些靜態(tài)字段,定義了剪切板中可以存放的數(shù)據(jù)類型。使用Clipboard類可以向剪切板中放入數(shù)據(jù)。
如將文字放入剪切板,使用方法SetDataObject即可:Clipboard.SetDataObject("剪切板文字2"); 在讀取的時(shí)候,先判斷剪切板中是否有文字,然后再讀?。?/p>
IDataObject data = Clipboard.GetDataObject(); if (data.GetDataPresent(DataFormats.Text)) { label1.Text = data.GetData(DataFormats.Text).ToString(); }
將自定義的數(shù)據(jù)放置到剪切板,自定義一個(gè)圖片類,并標(biāo)記為可序列化(此處使用的命名空間是:TestClipboard)。將自定義數(shù)據(jù)類型對(duì)象放置到剪切板的關(guān)鍵是DataObject類,它實(shí)現(xiàn)了IDataObject接口。它就像一個(gè)容器,存放將被放置在剪切板上的數(shù)據(jù)。
[Serializable] public class MyPic { /// <summary> /// 圖片 /// </summary> public Image Img; /// <summary> /// 圖片信息 /// </summary> public string ImgInfo; } public void SetMyPicToClipboard() { MyPic obj = new MyPic(); obj.Img = Properties.Resources.Image; obj.ImgInfo = "測(cè)試將自定義類型保存至剪切板"; //創(chuàng)建數(shù)據(jù)對(duì)象,并將數(shù)據(jù)裝入 IDataObject dataObj = new DataObject(obj); //其他類型也可以放置在同一數(shù)據(jù)對(duì)象中 /* dataObj.SetData(DataFormats.UnicodeText, "測(cè)試文字"); dataObj.SetData(DataFormats.Bitmap, Properties.Resources.Image); */ //復(fù)制到剪切板,第二個(gè)參數(shù)表示程序退出時(shí)不清空 Clipboard.SetDataObject(dataObj, true); }
但是,使用Clipboard.SetDataObject方法將一個(gè)DataObject對(duì)象放到剪切板后,外界訪問(wèn)時(shí),需要指定對(duì)象的完整類型名稱。如果某種數(shù)據(jù)類型只能在指定的進(jìn)程中訪問(wèn),則可以使用該方式,指定命名空間。
//首先判斷剪切板上是否有我的數(shù)據(jù):需要完全限定命名空間類型 if (Clipboard.ContainsData("WindowsFormsApplication1.MyPic")) { IDataObject dataObj = Clipboard.GetDataObject();//讀取數(shù)據(jù) MyPic myPic = dataObj.GetData("WindowsFormsApplication1.MyPic") as MyPic;//轉(zhuǎn)換數(shù)據(jù) pictureBox1.Image = myPic.Img; textBox1.Text = myPic.ImgInfo; }
2、使用FileSystemWatcher實(shí)現(xiàn)進(jìn)程同步
該組件可以監(jiān)控特定的文件夾或文件,比如在此文件夾中某文件被刪除或內(nèi)容被改變時(shí)引發(fā)對(duì)應(yīng)的事件。通過(guò)該組件讓多個(gè)進(jìn)程同時(shí)監(jiān)控一個(gè)文件,以此可以充當(dāng)“臨時(shí)”進(jìn)程間通信渠道。
實(shí)現(xiàn)進(jìn)程同步的關(guān)鍵點(diǎn)是:正確設(shè)置文件的共享和讀寫權(quán)限。
/// <summary> /// 實(shí)現(xiàn)寫入數(shù)據(jù) /// </summary> /// <param name="fileName"></param> public void SetText(string fileName) { using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.Read)) { using (StreamWriter writer = new StreamWriter(fs, Encoding.UTF8)) { writer.Write("內(nèi)容"); } } } /// <summary> /// 實(shí)現(xiàn)讀取數(shù)據(jù) /// </summary> /// <param name="fileName"></param> public void ReadText(string fileName) { using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { using (StreamReader reader = new StreamReader(fs, Encoding.UTF8)) { string txt = reader.ReadToEnd(); } } }
然后,使用FileSystemWatcher組件的Changed事件監(jiān)控文件是否發(fā)生改變。在網(wǎng)絡(luò)應(yīng)用程序中,可以使用此組件監(jiān)控特定的專用于上傳文件的文件夾,當(dāng)發(fā)現(xiàn)用戶上傳文件之后,系統(tǒng)可以自動(dòng)啟動(dòng)一系列的處理流程。
3、使用內(nèi)存映射文件(Memory Mapped File)實(shí)現(xiàn)進(jìn)程通信
含義:在內(nèi)存中開(kāi)辟一塊存放數(shù)據(jù)的專用區(qū)域,這區(qū)域與硬盤上特定的文件相對(duì)應(yīng)。進(jìn)程將這塊內(nèi)存區(qū)域映射到自己的地址空間中,完成像訪問(wèn)普通內(nèi)存一樣訪問(wèn)它。windows中的系統(tǒng)分頁(yè)文件和休眠文件就是如此實(shí)現(xiàn)的。需要引用命名空間System.IO.MemoryMappedFiles。
MemoryMappedFile對(duì)象表示一個(gè)內(nèi)存映射文件,通過(guò)它的CreateFromFile方法根據(jù)磁盤現(xiàn)有文件創(chuàng)建內(nèi)存映射文件(注意,使用完后要立即釋放資源,實(shí)際上它對(duì)應(yīng)的是操作系統(tǒng)的核心對(duì)象)。其中,內(nèi)存映射的容量在未指定時(shí),默認(rèn)與文件大小相等。在指定大小時(shí),它的值不能小于文件的現(xiàn)有大小。若指定的大小大于磁盤文件大小,磁盤文件會(huì)自動(dòng)增長(zhǎng)到內(nèi)存映射文件聲明的容量大小。
創(chuàng)建MemoryMappedFile對(duì)象后,不能直接對(duì)其進(jìn)行讀寫,必須使用MemoryMappedViewAccessor對(duì)象(內(nèi)存映射視圖訪問(wèn)對(duì)象)操作 ??梢杂肕emoryMappedFile對(duì)象的方法創(chuàng)建一個(gè)訪問(wèn)對(duì)象。其中,可以指定需要訪問(wèn)文件的范圍,從第幾個(gè)字節(jié)到第幾個(gè)字節(jié)。在寫入?yún)?shù)時(shí),也需要指明想哪個(gè)位置寫入什么。同時(shí)也可以使用MemoryMappedViewAccessor的Read方法讀取數(shù)據(jù)。
MemoryMappedFile memoryFile = MemoryMappedFile.CreateFromFile("Text.Config", FileMode.OpenOrCreate, "Config", 1400);//kb; MemoryMappedViewAccessor accessor = memoryFile.CreateViewAccessor(0, 1024); accessor.Write(0, '2');
在同一個(gè)進(jìn)程中,可以針對(duì)同一個(gè)內(nèi)存映射文件創(chuàng)建多個(gè)“內(nèi)存映射視圖訪問(wèn)對(duì)象”,從而允許同時(shí)修改同一個(gè)文件的不同部分,在關(guān)閉這些對(duì)象時(shí),由操作系統(tǒng)保證將所有修改都寫回原始文件。
MemoryMappedViewAccessor 的Write和Read有泛型方法,單類型只能是結(jié)構(gòu)體類型(應(yīng)用類型在程序運(yùn)行時(shí),計(jì)算機(jī)無(wú)法知道應(yīng)該向內(nèi)存映射文件寫入多少字節(jié)數(shù)據(jù),引用類型的對(duì)象位于托管堆中,其大小需要經(jīng)過(guò)計(jì)算,但非常耗時(shí)(而且對(duì)象可能引用了其他對(duì)象),音效內(nèi)存映射文件的效率)。
可以使用序列化方式,將引用對(duì)象數(shù)據(jù)進(jìn)行序列化后,寫入內(nèi)存映射文件中。
MemoryMappedFile memoryFile = MemoryMappedFile.CreateFromFile("Text.Config", FileMode.OpenOrCreate, "Config", 1400);//kb; MemoryMappedViewStream stream = memoryFile.CreateViewStream(); MyPic obj = new MyPic(); stream.Seek(0, SeekOrigin.Begin); new BinaryFormatter().Serialize(stream, obj);
4、使用WCF通過(guò)管道實(shí)現(xiàn)進(jìn)程通信
“管道(Pipe)”是Windows所提供的一種進(jìn)程間通信機(jī)制,用于在兩個(gè)進(jìn)程間相互傳送數(shù)據(jù)。Windows提供了兩種類型管道:匿名管道(Anonymous Pipe)、命名管道(Named Pipe)
- 匿名管道:只允許單向通信,由于沒(méi)有名字,因此要通信的兩個(gè)進(jìn)程應(yīng)該是父子關(guān)系,父進(jìn)程在創(chuàng)建子進(jìn)程時(shí),負(fù)責(zé)將代表匿名管道的句柄傳送給子進(jìn)程,子進(jìn)程可以通過(guò)該句柄獲取父進(jìn)程傳輸?shù)臄?shù)據(jù)。其優(yōu)點(diǎn)是占用資源少、效率高;缺點(diǎn)是通信進(jìn)程必須為父子關(guān)系,限制了使用場(chǎng)景。
- 命名管道:這種類型的管道擁有一個(gè)在本機(jī)唯一的名字,可以用于在一個(gè)服務(wù)進(jìn)程和多個(gè)客戶進(jìn)程之間進(jìn)行單/雙向通信。命名管道是基于消息的通信模式,即一個(gè)進(jìn)程一次可以向另一方進(jìn)程連續(xù)發(fā)生多個(gè)消息(消息之間通過(guò)消息的定界符進(jìn)行劃分),接收方通過(guò)定界符提取完整的消息。
在命名空間System.IO.Pipes中,提供了一些用于實(shí)現(xiàn)基于管道的進(jìn)程間通信,如AnonymousPipeClientStream和AnonymousPipeServerStream可用于實(shí)現(xiàn)匿名管道,而NamedPipeClientStream和NamedPipeServerStream可以實(shí)現(xiàn)命名管道。但相對(duì)于WCF,其比較繁瑣,WCF的管道進(jìn)程通信更加簡(jiǎn)便和靈活。
WCF應(yīng)用程序使用命名管道實(shí)現(xiàn)進(jìn)程通信:WCF提供了一個(gè)NetNamedPipeBinding綁定,它可以在地層使用命名管道實(shí)現(xiàn)進(jìn)程通信。
以上就是c# 如何實(shí)現(xiàn)不同進(jìn)程之間的通信的詳細(xì)內(nèi)容,更多關(guān)于c# 進(jìn)程通信的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
WPF中下拉框可作選擇項(xiàng)也可以作為只讀文本框使用的方法
這篇文章主要給大家介紹了關(guān)于WPF中下拉框可以選擇項(xiàng)也可以作為只讀文本框使用的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-02-02基于C#實(shí)現(xiàn)Windows服務(wù)的方法詳解
在實(shí)際應(yīng)用過(guò)程中,有時(shí)候我們希望開(kāi)發(fā)的程序,不需要界面,直接開(kāi)機(jī)就可以長(zhǎng)時(shí)間運(yùn)行,這時(shí)候,我們可以考慮做成一個(gè)Windows服務(wù)。這篇文章跟大家介紹一下,如何基于C#實(shí)現(xiàn)Windows服務(wù)的創(chuàng)建、安裝、啟動(dòng)、停止和卸載,需要的可以參考一下2022-09-09C#實(shí)現(xiàn)JSON字符串序列化與反序列化的方法
在這篇文章中,我們將會(huì)學(xué)到如何使用C#,來(lái)序列化對(duì)象成為Json格式的數(shù)據(jù),以及如何反序列化Json數(shù)據(jù)到對(duì)象。2017-01-01詳解C#如何使用重載方法實(shí)現(xiàn)不同類型數(shù)據(jù)的計(jì)算
這篇文章主要為大家詳細(xì)介紹了C#如何使用重載方法實(shí)現(xiàn)不同類型數(shù)據(jù)的計(jì)算,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-02-02