科技行者

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

知识库

知识库 安全导航

至顶网软件频道基础软件在.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构造器的第二个参数应该是“.”。如果不在同一台机器上,第二个参数就是服务器的网络名称。

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

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

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