科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件在.NET中使用命名管道完成进程间通信

在.NET中使用命名管道完成进程间通信

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

通常来说,Remoting是很不错的,但如果仅限于本地机器的两个进程间相互通信,其处理机制增加了不必要的开销

作者:戴飞 来源:程序员 2007年11月3日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
五、创建命名管道服务器

  命名管道服务器是一个多线程的引擎,用来为并发的请求服务,创建新的线程和管道连接。

  AppModule.NamedPipes assembly包含了一个基类ApipeConnection,是对普通命名管道操作的封装,例如创建管道、读写数据等等,这是一个抽象类。

  另外,有两个从ApipeConnection继承的管道连接类ClientPipeConnection 和 ServerPipeConnection。它们重载了一些方法(例如连接和关闭)并为服务器和客户端命名管道分别提供实现。ClientPipeConnection 和ServerPipeConnection都有调用Dispose方法的析构器,
清除非管控的资源。

  命名管道服务器负责创建命名管道,处理客户端连接。有两个主要的类提供了服务功能: ServerNamedPipe和PipeManager。

  (1)ServerNamedPipe类

  其构造器如下:..

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;
}

  构造器创建了一个新的ServerPipeConnection实例,并调用PipeListener方法。随后的主要部分是循环监听客户端连接,以及读写数据。

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;
   // 从客户端管道读取数据:
   stringrequest=PipeConnection.Read();
   LastAction=DateTime.Now;
   if(request.Trim()!=""){
    //PipeManager.HandleRequest 方法接受客户端请求处理之,
    // 然后进行响应,这个响应接着就被写入管道。
    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;
   // 从客户端管道断开连接
   PipeConnection.Disconnect();
   if(Listen){
    Form1.ActivityRef.AppendText("Pipe"+this.PipeConnection. NativeHandle.ToString()+":listening"+Environment.NewLine);

    // 开始监听一个新的连接:

    Connect(); }
   Form1.PipeManager.WakeUp();
  }
 }
 catch(System.Threading.ThreadAbortExceptionex){}
 catch(System.Threading.ThreadStateExceptionex){}
 catch(Exceptionex){
  //Logexception
 }
 finally{
  this.Close();}
 }

  请注意不要关闭服务器管道,因为创建一个服务器管道是一个相对昂贵的操作,会引起比较昂贵的开销。

  (2)PipeManager 类

  PipeManager 类负责在必要的时候创建服务器管道,管理线程,并生成客户端请求的响应。下面代码中Initialize方法调用Start方法创建一个新的线程:

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类只在获得请求的时候才创建新的管道连接和线程。这意味着ServerPipeConnection对象只在没有连接存在或所有连接都忙于响应请求的时候才被创建。通常2-3个命名管道实例就能处理很大负载的并发客户端请求,但这个主要取决于处理客户端请求和生
成响应的时间。

  创建ServerPipeConnection对象的引用被保存在管道哈希表中。

private void Start() {
 try{

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

   // 循环检验ServerPipeConnection 对象是否还是可用:
   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 字段包含了可以在服务器上拥有的命名管道最大数目
   if(numChannels<=NumberPipes){
    ServerNamedPipe pipe = new ServerNamedPipe(PipeName,OutBuffer,InBuffer,MAX_READ_BYTES);
    try{
     //Connect 方法将新生成的管道置为监听模式。
     pipe.Connect();
     pipe.LastAction=DateTime.Now;
     System.Threading.Interlocked.Increment(refnumChannels);
     // 开始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 }
}

  六、创建客户端管道连接

  要使用命名管道把一个客户端应用程序连接到服务器,我们必须创建ClientPipeConnection类的一个实例,使用它的方法来读写数据。

IInterProcessConnectionclientConnection=null;

try{
 clientConnection=newClientPipeConnection("MyPipe",".");
 clientConnection.Connect();
 clientConnection.Write(textBox1.Text);
 clientConnection.Close();
}
catch{
 clientConnection.Dispose();
}

  管道名称“MyPipe” 必须和服务器管道的名称一样,如果命名管道服务器也在同一台机器上,ClientPipeConnection构造器的第二个参数应该是“.”。如果不在同一台机器上,第二个参数就是服务器的网络名称。

  以上,我介绍了命名管道的解决方案,我再重申一下,命名管道最有效的使用是在一个应用程序需要和另一个应用程序进行非常频繁的,短文本的消息通信的情况下,并且是在同一台机器或在局域网内部。如果您遇到了这样的情况,希望我的这些代码能给你启发和参考。

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    闂傚倸鍊搁崐椋庢閿熺姴鐭楅幖娣妼缁愭鏌¢崶鈺佷汗闁哄閰i弻鏇$疀鐎n亞浠炬繝娈垮灠閵堟悂寮婚弴锛勭杸閻庯綆浜栭崑鎾诲冀椤撱劎绋忛梺璺ㄥ櫐閹凤拷

    濠电姷鏁告慨鐑姐€傛禒瀣劦妞ゆ巻鍋撻柛鐔锋健閸┾偓妞ゆ巻鍋撶紓宥咃躬楠炲啫螣鐠囪尙绐為梺褰掑亰閸撴盯鎮惧ú顏呪拺闂傚牊鍗曢崼銉ョ柧婵犲﹤瀚崣蹇旂節婵犲倻澧涢柛瀣ㄥ妽閵囧嫰寮介妸褋鈧帡鏌熼挊澶婃殻闁哄瞼鍠栭幃婊堝煛閸屾稓褰嬮柣搴ゎ潐濞叉ê鐣濈粙璺ㄦ殾闁割偅娲栭悡娑㈡煕鐏炲墽鐭嬫繛鍫熸倐濮婄粯鎷呯粵瀣異闂佹悶鍔嬮崡鍐茬暦閵忋倕鍐€妞ゆ劑鍎卞皬闂備焦瀵х粙鎴犫偓姘煎弮瀹曚即宕卞Ο闀愮盎闂侀潧鐗嗛幊搴㈡叏椤掆偓閳规垿鍩ラ崱妞剧凹濠电姰鍨洪敋閾荤偞淇婇妶鍛櫤闁稿鍊圭换娑㈠幢濡纰嶉柣搴㈣壘椤︾敻寮诲鍫闂佸憡鎸鹃崰搴敋閿濆鏁嗗〒姘功閻绻涢幘鏉戠劰闁稿鎹囬弻锝呪槈濞嗘劕纾抽梺鍝勬湰缁嬫垿鍩為幋锕€宸濇い鏇炴噺閳诲﹦绱撻崒娆戝妽妞ゃ劌鎳橀幆宀勫磼閻愰潧绁﹂柟鍏肩暘閸斿矂鎮為崹顐犱簻闁圭儤鍨甸鈺呮倵濮橆剦妲归柕鍥у瀵粙濡歌閸c儳绱撴担绛嬪殭婵☆偅绻堝濠氭偄绾拌鲸鏅i悷婊冪Ч閹﹢鎳犻鍌滐紲闁哄鐗勯崝搴g不閻愮儤鐓涢悘鐐跺Г閸犳﹢鏌℃担鐟板鐎规洜鍠栭、姗€鎮╅搹顐ら拻闂傚倷娴囧畷鍨叏閹惰姤鈷旂€广儱顦崹鍌炴煢濡尨绱氶柨婵嗩槸缁€瀣亜閺嶃劎鈽夋繛鍫熺矒濮婅櫣娑甸崨顔俱€愬銈庡亝濞茬喖宕洪埀顒併亜閹哄棗浜鹃梺鎸庢穿婵″洤危閹版澘绫嶉柛顐g箘椤撴椽姊虹紒妯哄鐎殿噮鍓欒灃闁告侗鍠氶崢鎼佹⒑閸撴彃浜介柛瀣閹﹢鏁冮崒娑氬幈闁诲函缍嗛崑鍡樻櫠椤掑倻纾奸柛灞剧☉缁椦囨煙閻熸澘顏柟鐓庢贡閹叉挳宕熼棃娑欐珡闂傚倸鍊风粈渚€骞栭銈傚亾濮樺崬鍘寸€规洖缍婇弻鍡楊吋閸涱垽绱遍柣搴$畭閸庨亶藝娴兼潙纾跨€广儱顦伴悡鏇㈡煛閸ャ儱濡煎褜鍨伴湁闁绘ǹ绉鍫熺畳闂備焦瀵х换鍌毼涘Δ鍛厺闁哄洢鍨洪悡鍐喐濠婂牆绀堟慨妯挎硾閽冪喖鏌曟繛褍瀚烽崑銊╂⒑缂佹ê濮囨い鏇ㄥ弮閸┿垽寮撮姀鈥斥偓鐢告煥濠靛棗鈧懓鈻嶉崶銊d簻闊洦绋愰幉楣冩煛鐏炵偓绀嬬€规洟浜堕、姗€鎮㈡總澶夌处

    重磅专题
    往期文章
    最新文章