国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

在.NET中使用命名管道完成進(jìn)程間通信

2019-11-17 04:53:31
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

  你曾經(jīng)需要在同一臺(tái)機(jī)器的兩個(gè).NET應(yīng)用程序間進(jìn)行數(shù)據(jù)交換嗎?例如,一個(gè)Web站點(diǎn)和一個(gè)Windows服務(wù)?.NET框架提供了幾種好的選擇來(lái)完成進(jìn)程間通信(ipC):Web Service,Remoting。最快的是Remoting,因?yàn)樗褂肨CP通道和二進(jìn)制格式。

  然而,假如需要頻繁地從一個(gè)應(yīng)用程序調(diào)用另外一個(gè)應(yīng)用程序,并且你主要關(guān)心的是性能,Remoting還是顯得慢了一點(diǎn)。讓Remoting變慢的,不是協(xié)議,而是序列化。

  通常來(lái)說(shuō),Remoting是很不錯(cuò)的,但假如僅限于本地機(jī)器的兩個(gè)進(jìn)程間相互通信,其處理機(jī)制增加了不必要的開(kāi)銷。所以要考慮一些別的選擇,比較好的是命名管道(Named Pipes),不會(huì)進(jìn)行二進(jìn)制序列化,所以提供了更快的IPC。

  要記住,這個(gè)解決方案最有效的使用是在一個(gè)應(yīng)用程序需要和另一個(gè)應(yīng)用程序進(jìn)行非常頻繁的、短文本的消息通信的情況下,并且是在同一臺(tái)機(jī)器或在同一局域網(wǎng)內(nèi)部。對(duì)于結(jié)構(gòu)化的數(shù)據(jù)交換,這些文本消息也可以是xml文檔或序列化的.NET對(duì)象。通信時(shí)沒(méi)有安全層,因?yàn)槊艿雷疃嘀荒茉诰钟蚓W(wǎng)中運(yùn)行,所以假定安全問(wèn)題由別的層進(jìn)行處理。

  一、實(shí)現(xiàn)命名管道

  以下是.NET命名管道解決方案中幾個(gè)主要的類。

  . NamedPipeNative:這個(gè)類和kernal32.dll聯(lián)系實(shí)現(xiàn)命名管道的通信,其中包含一些常用方法和常量。
 
  . NamedPipeWrapper :這個(gè)類是NamedPipeNative的一個(gè)包裝。

  . ApipeConnection:這是一個(gè)抽象類,定義了命名管道連接、讀、寫(xiě)數(shù)據(jù)的方法。這個(gè)類是從ClientPipeConnection 和ServerPipeConnection 繼續(xù)的,分別在客戶端和服務(wù)器端應(yīng)用程序中使用。

  . ClientPipeConnection:被客戶端應(yīng)用程序使用,使用命名管道和服務(wù)器通信。

  . ServerPipeConnection:答應(yīng)命名管道服務(wù)器創(chuàng)建連接,和客戶端進(jìn)行通信。

  . PipeHandle:保存操作系統(tǒng)的本地句柄,以及管道連接的當(dāng)前狀態(tài)。

  了解上述的類之后,需要了解一下命名管道的操作。

  二、創(chuàng)建一個(gè)服務(wù)器端命名管道

  服務(wù)器端管道名的語(yǔ)法是://./pipe/PipeName?!癙ipeName”.. 部分是管道的具體名字。要連接管道,客戶端應(yīng)用程序需要?jiǎng)?chuàng)建一個(gè)同樣名稱的客戶端命名管道。假如客戶端在不同的機(jī)器上,服務(wù)器端管道的名稱應(yīng)該是//SERVER/pipe/PipeName。下面的代碼是NamedPipeWrapper的一個(gè)靜態(tài)方法,被用來(lái)實(shí)例化一個(gè)服務(wù)器端命名管道。

public static PipeHandle Create(string name,uintoutBuffer, uintinBuffer){
 name = @"/./pipe/" + name;
 PipeHandle handle = new PipeHandle();

 for(inti=1;i<=ATTEMPTS;i++){
  handle.State=InterPRocessConnectionState.Creating;
  handle.Handle = NamedPipeNative.CreateNamedPipe( name,
   NamedPipeNative.PIPE_access_DUPLEX,
   NamedPipeNative.PIPE_TYPE_MESSAGE
   NamedPipeNative.PIPE_READMODE_MESSAGE
   NamedPipeNative.PIPE_WAIT,
   NamedPipeNative.PIPE_UNLIMITED_INSTANCES,
   outBuffer,
   inBuffer,
   NamedPipeNative.NMPWAIT_WAIT_FOREVER,
   IntPtr.Zero);
  if(handle.Handle.ToInt32()!=NamedPipeNative.INVALID_HANDLE_VALUE){
   handle.State=InterProcessConnectionState.Created;
   break;
 }

 if (i >= ATTEMPTS) {
  handle.State = InterProcessConnectionState.Error;
  throw new NamedPipeIOException("Error creating named
pipe"+name+".Internalerror:"+NamedPipeNative.GetLastError().ToString(),NamedPipeNative.GetLastError());
 }
}
returnhandle;
}
  通過(guò)調(diào)用NamedPipeNative.CreateNamedPipe方法,上面的方法創(chuàng)建了一個(gè)雙方互通的命名管道,并且指定管道可以有無(wú)限制的實(shí)例。常量的名稱都是英語(yǔ),不難看懂,就不一一解釋了。

  假定服務(wù)器端命名管道創(chuàng)建成功,它就可以開(kāi)始監(jiān)聽(tīng)客戶端連接了。

  三、連接到客戶端管道

  命名管道服務(wù)器需要設(shè)置成監(jiān)聽(tīng)狀態(tài),以使客戶端管道能夠連接它。這可以由調(diào)用NamedPipeNative.ConnectNamedPipe方法完成。

  調(diào)用NamedPipeNative.CreateFile方法,就可以創(chuàng)建一個(gè)命名管道客戶端,并且連接到一個(gè)監(jiān)聽(tīng)的服務(wù)器管道。下面的代碼是NamedPipeWrapper.ConnectToPipe的一部分,可以闡釋這一點(diǎn)。


public static PipeHandle ConnectToPipe(string pipeName, string serverName) {
 PipeHandle handle = new PipeHandle();
 //Buildthename ofthe pipe.
 string name = @"/" + serverName + @"/pipe/" + pipeName;
 for(inti=1;i<=ATTEMPTS;i++){
  handle.State = InterProcessConnectionState.ConnectingToServer;
  // Try to connect to the server
  handle.Handle = NamedPipeNative.CreateFile(name, NamedPipeNative.GENERIC_READ NamedPipeNative.
GENERIC_WRITE, 0,null,NamedPipeNative.OPEN_EXISTING,0,0);
  在創(chuàng)建一個(gè)PipeHandle對(duì)象并建立管道名稱后,我們調(diào)用NamedPipeNative.CreateFile方法來(lái)創(chuàng)建一個(gè)客戶端命名管道,并連接到指定的服務(wù)器端管道。在我們的例子中,客戶端管道被配置為可讀可寫(xiě)的。

  假如客戶端管道被成功創(chuàng)建,NamedPipeNative.CreateFile方法返回其對(duì)應(yīng)的本地句柄,這在以后的操作中會(huì)用到。假如由于某種原因創(chuàng)建失敗,方法會(huì)返回1, 并把NamedPipeNative設(shè)為INVALID_HANDLE_VALUE常量。

  在客戶端命名管道可以用來(lái)讀和寫(xiě)之前,還要做一件事情。我們需要把handle 設(shè)為PIPE_READMODE_MESSAGE??梢哉{(diào)用NamedPipeNative.SetNamed-PipeHandleState 實(shí)現(xiàn)。

if (handle.Handle.ToInt32() != NamedPipeNative.INVALID_HANDLE_VALUE){
 // The client managed to connect to the server pipe
 handle.State = InterProcessConnectionState.

 ConnectedToServer;
 // Set the read mode of the pipe channel
 uint mode = NamedPipeNative.PIPE_READMODE_MESSAGE;

 if(NamedPipeNative.SetNamedPipeHandleState(handle.Handle,refmode,IntPtr.Zero,IntPtr.Zero)){
  break;
 }
  每個(gè)客戶端管道和一個(gè)服務(wù)器管道的實(shí)例通信。若服務(wù)器端的實(shí)例達(dá)到最大數(shù)目,創(chuàng)建客戶端管道會(huì)失敗。

  四、讀寫(xiě)數(shù)據(jù)

  從命名管道讀數(shù)據(jù)時(shí)我們不能提前知道消息的長(zhǎng)度。我們的解決方案不需要處理很長(zhǎng)的消息,所以使用System.Int32變量來(lái)指定消息的長(zhǎng)度。

  NamedPipeWrapper.WriteBytes 方法可以將消息寫(xiě)到一個(gè)命名管道,消息按UTF8編碼,然后按字節(jié)數(shù)組傳遞。

public static void WriteBytes(PipeHandle handle, byte[]bytes) {
 byte[] numReadWritten = new byte[4];
 uint len;

 if(bytes==null){
  bytes=newbyte[0];
 }
 if (bytes.Length == 0) {
  bytes = new byte[1];
  bytes = System.Text.Encoding.UTF8.GetBytes(" ");
 }
 // 獲取消息的長(zhǎng)度:
 len= (uint)bytes.Length;

 handle.State = InterProcessConnectionState.Writing;
 // 獲取消息長(zhǎng)度的字節(jié)表示,先寫(xiě)這四字節(jié)
 if(NamedPipeNative.WriteFile(handle.Handle,BitConverter.GetBytes(len),4,numReadWritten,0)){
  // 寫(xiě)余下的消息
  if(!NamedPipeNative.WriteFile(handle.Handle,bytes,len,numReadWritten,0)){
   handle.State=InterProcessConnectionState.Error;
   thrownewNamedPipeIOException("Errorwritingtopipe. Internalerror:"+NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError());
  }
 }
 else{
  handle.State=InterProcessConnectionState.Error;
  thrownewNamedPipeIOException("Errorwritingtopipe.Internalerror:"+NamedPipeNative.GetLastError().ToString(),
NamedPipeNative.GetLastError());
 }

 handle.State =InterProcessConnectionState.Flushing;
 // 激活管道,保證任何緩存數(shù)據(jù)都被寫(xiě)入管道,不會(huì)丟失:
 Flush(handle);
 handle.State = InterProcessConnectionState.FlushedData;
}
  要從一個(gè)命名管道讀數(shù)據(jù),先要把前四個(gè)字節(jié)轉(zhuǎn)化為整數(shù)以確定消息的長(zhǎng)度。接著,就可以讀余下的數(shù)據(jù)了,請(qǐng)看下面的NamedPipeWrapper.ReadBytes方法。


public static byte[] ReadBytes(PipeHandle handle, int maxBytes) {
 byte[]numReadWritten=newbyte[4];
 byte[]intBytes=newbyte[4];
 byte[]msgBytes=null;
 intlen;

 handle.State=InterProcessConnectionState.Reading;
 handle.State=InterProcessConnectionState.Flushing;
 // 讀前四個(gè)字節(jié)并轉(zhuǎn)化為整數(shù):
 if(NamedPipeNative.ReadFile(handle.Handle, intBytes,4, numReadWritten, 0)) {
  len=BitConverter.ToInt32(intBytes,0);
  msgBytes=newbyte[len];
  handle.State=InterProcessConnectionState.Flushing;
  // 讀余下的數(shù)據(jù)或拋出異常:
  if(!NamedPipeNative.ReadFile(handle.Handle,msgBytes,(uint) len,numReadWritten,0)){
   handle.State=InterProcessConnectionState.Error;
   thrownewNamedPipeIOException("Error readingfrompipe. Internalerror:"+NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError());
  }
 }
 else {
  handle.State=InterProcessConnectionState.Error;
  thrownewNamedPipeIOException("Errorreadingfrompipe. Internalerror:"+NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError());
 }
 handle.State=InterProcessConnectionState.ReadData;
 if(len>maxBytes){
  returnnull; }
 returnmsgBytes;
}
  以上就是命名管道的實(shí)現(xiàn)和一些主要的方法,下面介紹如何創(chuàng)建進(jìn)行文本消息通信的命名管道服務(wù)器和客戶端應(yīng)用程序。 QQRead.com 推出數(shù)據(jù)恢復(fù)指南教程 數(shù)據(jù)恢復(fù)指南教程 數(shù)據(jù)恢復(fù)故障解析 常用數(shù)據(jù)恢復(fù)方案 硬盤(pán)數(shù)據(jù)恢復(fù)教程 數(shù)據(jù)保護(hù)方法 數(shù)據(jù)恢復(fù)軟件 專業(yè)數(shù)據(jù)恢復(fù)服務(wù)指南 五、創(chuàng)建命名管道服務(wù)器

  命名管道服務(wù)器是一個(gè)多線程的引擎,用來(lái)為并發(fā)的請(qǐng)求服務(wù),創(chuàng)建新的線程和管道連接。

  AppModule.NamedPipes assembly包含了一個(gè)基類ApipeConnection,是對(duì)普通命名管道操作的封裝,例如創(chuàng)建管道、讀寫(xiě)數(shù)據(jù)等等,這是一個(gè)抽象類。

  另外,有兩個(gè)從ApipeConnection繼續(xù)的管道連接類ClientPipeConnection 和 ServerPipeConnection。它們重載了一些方法(例如連接和關(guān)閉)并為服務(wù)器和客戶端命名管道分別提供實(shí)現(xiàn)。ClientPipeConnection 和ServerPipeConnection都有調(diào)用Dispose方法的析構(gòu)器,
清除非管控的資源。

  命名管道服務(wù)器負(fù)責(zé)創(chuàng)建命名管道,處理客戶端連接。有兩個(gè)主要的類提供了服務(wù)功能: ServerNamedPipe和PipeManager。

 ?。?)ServerNamedPipe類

  其構(gòu)造器如下:..

internal ServerNamedPipe(stringname, uint outBuffer,uintinBuffer,intmaxReadBytes){
 PipeConnection=newServerPipeConnection(name,outBuffer,inBuffer,maxReadBytes);
 PipeThread=newThread(newThreadStart(PipeListener));
 PipeThread.IsBackground=true;

 PipeThread.Name ="PipeThread "+this.PipeConnection.NativeHandle.ToString();
 LastAction=DateTime.Now;
}
  構(gòu)造器創(chuàng)建了一個(gè)新的ServerPipeConnection實(shí)例,并調(diào)用PipeListener方法。隨后的主要部分是循環(huán)監(jiān)聽(tīng)客戶端連接,以及讀寫(xiě)數(shù)據(jù)。

private void PipeListener() {
 CheckIfDisposed();

 try{
  Listen=Form1.PipeManager.Listen;
  Form1.ActivityRef.AppendText("Pipe"+this.PipeConnection.NativeHandle.ToString() + ": new pipe started" + Environment.NewLine);
  while(Listen){
   LastAction=DateTime.Now;
   // 從客戶端管道讀取數(shù)據(jù):
   stringrequest=PipeConnection.Read();
   LastAction=DateTime.Now;
   if(request.Trim()!=""){
    //PipeManager.HandleRequest 方法接受客戶端請(qǐng)求處理之,
    // 然后進(jìn)行響應(yīng),這個(gè)響應(yīng)接著就被寫(xiě)入管道。
    PipeConnection.Write(Form1.PipeManager.HandleRequest(request));
    Form1.ActivityRef.AppendText("Pipe"+this.PipeConnection.NativeHandle.ToString()+ ":requesthandled"+Environment.NewLine);
   }
   else{ PipeConnection.Write("Error:badrequest");}
   LastAction=DateTime.Now;
   // 從客戶端管道斷開(kāi)連接
   PipeConnection.Disconnect();
   if(Listen){
    Form1.ActivityRef.AppendText("Pipe"+this.PipeConnection. NativeHandle.ToString()+":listening"+Environment.NewLine);

    // 開(kāi)始監(jiān)聽(tīng)一個(gè)新的連接:

    Connect(); }
   Form1.PipeManager.WakeUp();
  }
 }
 catch(System.Threading.ThreadAbortExceptionex){}
 catch(System.Threading.ThreadStateExceptionex){}
 catch(Exceptionex){
  //Logexception
 }
 finally{
  this.Close();}
 }
  請(qǐng)注重不要關(guān)閉服務(wù)器管道,因?yàn)閯?chuàng)建一個(gè)服務(wù)器管道是一個(gè)相對(duì)昂貴的操作,會(huì)引起比較昂貴的開(kāi)銷。

 ?。?)PipeManager 類

  PipeManager 類負(fù)責(zé)在必要的時(shí)候創(chuàng)建服務(wù)器管道,治理線程,并生成客戶端請(qǐng)求的響應(yīng)。下面代碼中Initialize方法調(diào)用Start方法創(chuàng)建一個(gè)新的線程:


public void Initialize() {
 Pipes=Hashtable.Synchronized(_pipes);

 Mre =newManualResetEvent(false);
 MainThread =newThread(newThreadStart(Start));
 MainThread.IsBackground=true;
 MainThread.Name = "MainPipeThread";

 MainThread.Start();
 Thread.Sleep(1000);
}
  PipeManager類只在獲得請(qǐng)求的時(shí)候才創(chuàng)建新的管道連接和線程。這意味著ServerPipeConnection對(duì)象只在沒(méi)有連接存在或所有連接都忙于響應(yīng)請(qǐng)求的時(shí)候才被創(chuàng)建。通常2-3個(gè)命名管道實(shí)例就能處理很大負(fù)載的并發(fā)客戶端請(qǐng)求,但這個(gè)主要取決于處理客戶端請(qǐng)求和生
成響應(yīng)的時(shí)間。

  創(chuàng)建ServerPipeConnection對(duì)象的引用被保存在管道哈希表中。

private void Start() {
 try{

  while(_listen){
   int[]keys=newint[Pipes.Keys.Count];
   Pipes.Keys.CopyTo(keys,0);

   // 循環(huán)檢驗(yàn)ServerPipeConnection 對(duì)象是否還是可用:
   foreach(intkeyinkeys){
    ServerNamedPipeserverPipe=(ServerNamedPipe)Pipes[key];
    if(serverPipe!=null&& DateTime.Now.SuBTract(serverPipe.LastAction).Milliseconds>
PIPE_MAX_STUFFED_TIME && serverPipe.PipeConnection.GetState()!=InterProcessConnectionState.WaitingForClient){
     serverPipe.Listen=false;
     serverPipe.PipeThread.Abort();
     RemoveServerChannel(serverPipe.PipeConnection.NativeHandle);
    }
   }
   //NumberPipes 字段包含了可以在服務(wù)器上擁有的命名管道最大數(shù)目
   if(numChannels<=NumberPipes){
    ServerNamedPipe pipe = new ServerNamedPipe(PipeName,OutBuffer,InBuffer,MAX_READ_BYTES);
    try{
     //Connect 方法將新生成的管道置為監(jiān)聽(tīng)模式。
     pipe.Connect();
     pipe.LastAction=DateTime.Now;
     System.Threading.Interlocked.Increment(refnumChannels);
     // 開(kāi)始ServerPipeConnection 線程
     pipe.Start();
     Pipes.Add(pipe.PipeConnection.NativeHandle,pipe);
    }
    catch (InterProcessIOException ex) {
     RemoveServerChannel(pipe.PipeConnection.NativeHandle);
     pipe.Dispose();
    }
   }
   else{ Mre.Reset(); Mre.WaitOne(1000,false); }
  }
 }
 catch { //Logexception }
}
  六、創(chuàng)建客戶端管道連接

  要使用命名管道把一個(gè)客戶端應(yīng)用程序連接到服務(wù)器,我們必須創(chuàng)建ClientPipeConnection類的一個(gè)實(shí)例,使用它的方法來(lái)讀寫(xiě)數(shù)據(jù)。

IInterProcessConnectionclientConnection=null;

try{
 clientConnection=newClientPipeConnection("MyPipe",".");
 clientConnection.Connect();
 clientConnection.Write(textBox1.Text);
 clientConnection.Close();
}
catch{
 clientConnection.Dispose();
}
  管道名稱“MyPipe” 必須和服務(wù)器管道的名稱一樣,假如命名管道服務(wù)器也在同一臺(tái)機(jī)器上,ClientPipeConnection構(gòu)造器的第二個(gè)參數(shù)應(yīng)該是“.”。假如不在同一臺(tái)機(jī)器上,第二個(gè)參數(shù)就是服務(wù)器的網(wǎng)絡(luò)名稱。

  以上,我介紹了命名管道的解決方案,我再重申一下,命名管道最有效的使用是在一個(gè)應(yīng)用程序需要和另一個(gè)應(yīng)用程序進(jìn)行非常頻繁的,短文本的消息通信的情況下,并且是在同一臺(tái)機(jī)器或在局域網(wǎng)內(nèi)部。假如您碰到了這樣的情況,希望我的這些代碼能給你啟發(fā)和參考。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 华亭县| 醴陵市| 张北县| 丘北县| 衡东县| 松潘县| 区。| 乌什县| 平果县| 桐梓县| 蕉岭县| 彭水| 安龙县| 黎川县| 临邑县| 丰县| 岑溪市| 上高县| 临清市| 龙川县| 长汀县| 禹州市| 阿拉善盟| 仁布县| 定州市| 丹江口市| 乐至县| 玉田县| 长沙市| 石嘴山市| 昌平区| 托克托县| 嘉定区| 类乌齐县| 双流县| 瑞昌市| 霸州市| 湟中县| 察隅县| 惠水县| 蕉岭县|