兰色精灵 发表于 2015-1-16 22:35:22

ASP.NET编程:在.NET中利用定名管道完成历程间通讯

你觉得学习.NET怎么样,我懂的少,问的可能很幼稚,见笑了啊:)历程  你已经必要在统一台呆板的两个.NET使用程序间举行数据互换吗?比方,一个Web站点和一个Windows服务?.NET框架供应了几种好的选择来完成历程间通讯(IPC):WebService,Remoting。最快的是Remoting,由于它利用TCP通道和二进制格局。

  但是,假如必要频仍地从一个使用程序挪用别的一个使用程序,而且你次要体贴的是功能,Remoting仍是显得慢了一点。让Remoting变慢的,不是协定,而是序列化。

  一般来讲,Remoting是很不错的,但假如仅限于当地呆板的两个历程间互相通讯,其处置机制增添了不用要的开支。以是要思索一些其余选择,对照好的是定名管道(NamedPipes),不会举行二进制序列化,以是供应了更快的IPC。

  要记着,这个办理计划最无效的利用是在一个使用程序必要和另外一个使用程序举行十分频仍的、漫笔本的动静通讯的情形下,而且是在统一台呆板或在统一局域网外部。关于布局化的数据互换,这些文本动静也能够是XML文档或序列化的.NET工具。通讯时没有平安层,由于定名管道最多只能在局域网中运转,以是假定平安成绩由其余层举行处置。

  1、完成定名管道

  以下是.NET定名管道办理计划中几个次要的类。

  .NamedPipeNative:这个类和kernal32.dll接洽完成定名管道的通讯,个中包括一些经常使用办法和常量。
 
  .NamedPipeWrapper:这个类是NamedPipeNative的一个包装。

  .ApipeConnection:这是一个笼统类,界说了定名管道毗连、读、写数据的办法。这个类是从ClientPipeConnection和ServerPipeConnection承继的,分离在客户端和服务器端使用程序中利用。

  .ClientPipeConnection:被客户端使用程序利用,利用定名管道和服务器通讯。

  .ServerPipeConnection:同意定名管道服务器创立毗连,和客户端举行通讯。

  .PipeHandle:保留操纵体系的当地句柄,和管道毗连确当前形态。

  懂得上述的类以后,必要懂得一下定名管道的操纵。

  2、创立一个服务器端定名管道

  服务器端管道名的语法是:.pipePipeName。“PipeName”..部分是管道的详细名字。要毗连管道,客户端使用程序必要创立一个一样称号的客户端定名管道。假如客户端在分歧的呆板上,服务器端管道的称号应当是SERVERpipePipeName。上面的代码是NamedPipeWrapper的一个静态办法,被用来实例化一个服务器端定名管道。

publicstaticPipeHandleCreate(stringname,uintoutBuffer,uintinBuffer){
 name=@".pipe"+name;
 PipeHandlehandle=newPipeHandle();

 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;
  thrownewNamedPipeIOException("Errorcreatingnamed
pipe"+name+".Internalerror:"+NamedPipeNative.GetLastError().ToString(),NamedPipeNative.GetLastError());
 }
}
returnhandle;
}
  经由过程挪用NamedPipeNative.CreateNamedPipe办法,下面的办法创立了一个两边互通的定名管道,而且指定管道能够有没有限定的实例。常量的称号都是英语,不丢脸懂,就纷歧一注释了。

  假定服务器端定名管道创立乐成,它就能够入手下手监听客户端毗连了。

  3、毗连到客户端管道

  定名管道服务器必要设置成监听形态,以使客户端管道可以毗连它。这能够由挪用NamedPipeNative.ConnectNamedPipe办法完成。

  挪用NamedPipeNative.CreateFile办法,就能够创立一个定名管道客户端,而且毗连到一个监听的服务器管道。上面的代码是NamedPipeWrapper.ConnectToPipe的一部分,能够阐释这一点。

publicstaticPipeHandleConnectToPipe(stringpipeName,stringserverName){
 PipeHandlehandle=newPipeHandle();
 //Buildthenameofthepipe.
 stringname=@""+serverName+@"pipe"+pipeName;
 for(inti=1;i<=ATTEMPTS;i++){
  handle.State=InterProcessConnectionState.ConnectingToServer;
  //Trytoconnecttotheserver
  handle.Handle=NamedPipeNative.CreateFile(name,NamedPipeNative.GENERIC_READ|NamedPipeNative.
GENERIC_WRITE,0,null,NamedPipeNative.OPEN_EXISTING,0,0);
  在创立一个PipeHandle工具并创建管道称号后,我们挪用NamedPipeNative.CreateFile办法来创立一个客户端定名管道,并毗连到指定的服务器端管道。在我们的例子中,客户端管道被设置为可读可写的。

  假如客户端管道被乐成创立,NamedPipeNative.CreateFile办法前往其对应的当地句柄,这在今后的操纵中会用到。假如因为某种缘故原由创立失利,办法会前往1,并把NamedPipeNative设为INVALID_HANDLE_VALUE常量。

  在客户端定名管道能够用来读和写之前,还要做一件事变。我们必要把handle设为PIPE_READMODE_MESSAGE。能够挪用NamedPipeNative.SetNamed-PipeHandleState完成。

if(handle.Handle.ToInt32()!=NamedPipeNative.INVALID_HANDLE_VALUE){
 //Theclientmanagedtoconnecttotheserverpipe
 handle.State=InterProcessConnectionState.

 ConnectedToServer;
 //Setthereadmodeofthepipechannel
 uintmode=NamedPipeNative.PIPE_READMODE_MESSAGE;

 if(NamedPipeNative.SetNamedPipeHandleState(handle.Handle,refmode,IntPtr.Zero,IntPtr.Zero)){
  break;
 }
  每一个客户端管道和一个服务器管道的实例通讯。若服务器真个实例到达最年夜数量,创立客户端管道会失利。

  4、读写数据

  从定名管道读数据时我们不克不及提早晓得动静的长度。我们的办理计划不必要处置很长的动静,以是利用System.Int32变量来指定动静的长度。

  NamedPipeWrapper.WriteBytes办法能够将动静写到一个定名管道,动静按UTF8编码,然后按字节数组传送。

publicstaticvoidWriteBytes(PipeHandlehandle,byte[]bytes){
 byte[]numReadWritten=newbyte;
 uintlen;

 if(bytes==null){
  bytes=newbyte;
 }
 if(bytes.Length==0){
  bytes=newbyte;
  bytes=System.Text.Encoding.UTF8.GetBytes("");
 }
 //猎取动静的长度:
 len=(uint)bytes.Length;

 handle.State=InterProcessConnectionState.Writing;
 //猎取动静长度的字节暗示,先写这四字节
 if(NamedPipeNative.WriteFile(handle.Handle,BitConverter.GetBytes(len),4,numReadWritten,0)){
  //写余下的动静
  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;
 //激活管道,包管任何缓存数据都被写进管道,不会丧失:
 Flush(handle);
 handle.State=InterProcessConnectionState.FlushedData;
}
  要从一个定名管道读数据,先要把前四个字节转化为整数以断定动静的长度。接着,就能够读余下的数据了,请看上面的NamedPipeWrapper.ReadBytes办法。

publicstaticbyte[]ReadBytes(PipeHandlehandle,intmaxBytes){
 byte[]numReadWritten=newbyte;
 byte[]intBytes=newbyte;
 byte[]msgBytes=null;
 intlen;

 handle.State=InterProcessConnectionState.Reading;
 handle.State=InterProcessConnectionState.Flushing;
 //读前四个字节并转化为整数:
 if(NamedPipeNative.ReadFile(handle.Handle,intBytes,4,numReadWritten,0)){
  len=BitConverter.ToInt32(intBytes,0);
  msgBytes=newbyte;
  handle.State=InterProcessConnectionState.Flushing;
  //读余下的数据或抛出非常:
  if(!NamedPipeNative.ReadFile(handle.Handle,msgBytes,(uint)len,numReadWritten,0)){
   handle.State=InterProcessConnectionState.Error;
   thrownewNamedPipeIOException("Errorreadingfrompipe.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;
}
  以上就是定名管道的完成和一些次要的办法,上面先容怎样创立举行文本动静通讯的定名管道服务器和客户端使用程序。
<P>  5、创立定名管道服务器

  定名管道服务器是一个多线程的引擎,用来为并发的哀求服务,创立新的线程和管道毗连。

  AppModule.NamedPipesassembly包括了一个基类ApipeConnection,是对一般定名管道操纵的封装,比方创立管道、读写数据等等,这是一个笼统类。

  别的,有两个从ApipeConnection承继的管道毗连类ClientPipeConnection和ServerPipeConnection。它们重载了一些办法(比方毗连和封闭)并为服务器和客户端定名管道分离供应完成。ClientPipeConnection和ServerPipeConnection都有挪用Dispose办法的析构器,
扫除非管控的资本。

  定名管道服务器卖力创立定名管道,处置客户端毗连。有两个次要的类供应了服务功效:ServerNamedPipe和PipeManager。

  (1)ServerNamedPipe类

  其机关器以下:..

internalServerNamedPipe(stringname,uintoutBuffer,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办法。随后的次要部分是轮回监听客户端毗连,和读写数据。

privatevoidPipeListener(){
 CheckIfDisposed();

 try{
  Listen=Form1.PipeManager.Listen;
  Form1.ActivityRef.AppendText("Pipe"+this.PipeConnection.NativeHandle.ToString()+":newpipestarted"+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办法创立一个新的线程:

publicvoidInitialize(){
 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工具的援用被保留在管道哈希表中。

privatevoidStart(){
 try{

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

   //轮回查验ServerPipeConnection工具是不是仍是可用:
   foreach(intkeyinkeys){
    ServerNamedPipeserverPipe=(ServerNamedPipe)Pipes;
    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){
    ServerNamedPipepipe=newServerNamedPipe(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(InterProcessIOExceptionex){
     RemoveServerChannel(pipe.PipeConnection.NativeHandle);
     pipe.Dispose();
    }
   }
   else{Mre.Reset();Mre.WaitOne(1000,false);}
  }
 }
 catch{//Logexception}
}
  6、创立客户端管道毗连

  要利用定名管道把一个客户端使用程序毗连到服务器,我们必需创立ClientPipeConnection类的一个实例,利用它的办法来读写数据。

IInterProcessConnectionclientConnection=null;

try{
 clientConnection=newClientPipeConnection("MyPipe",".");
 clientConnection.Connect();
 clientConnection.Write(textBox1.Text);
 clientConnection.Close();
}
catch{
 clientConnection.Dispose();
}
  管道称号“MyPipe”必需和服务器管道的称号一样,假如定名管道服务器也在统一台呆板上,ClientPipeConnection机关器的第二个参数应当是“.”。假如不在统一台呆板上,第二个参数就是服务器的收集称号。

  以上,我先容了定名管道的办理计划,我再重申一下,定名管道最无效的利用是在一个使用程序必要和另外一个使用程序举行十分频仍的,漫笔本的动静通讯的情形下,而且是在统一台呆板或在局域网外部。假如您碰到了如许的情形,但愿我的这些代码能给你启示和参考。因为各系统的API不同,代码调用API编写程序就会遇到很多不兼容的地方,比如Java改写后的Serv-U就不能在手机上执行,手机的游戏也不能直接在微机上执行。

金色的骷髅 发表于 2015-1-19 17:51:42

ASP.Net摆脱了以前ASP使用脚本语言来编程的缺点,理论上可以使用任何编程语言包括C++,VB,JS等等,当然,最合适的编程语言还是MS为.NetFrmaework专门推出的C(读csharp)。

只想知道 发表于 2015-1-25 12:10:22

代码逻辑混乱,难于管理:由于ASP是脚本语言混合html编程,所以你很难看清代码的逻辑关系,并且随着程序的复杂性增加,使得代码的管理十分困难,甚至超出一个程序员所能达到的管理能力,从而造成出错或这样那样的问题。

愤怒的大鸟 发表于 2015-2-2 22:03:13

对于中小项目来说.net技术是完全可以胜任,但为什么现在大型公司或网站都选择php或java呢?就是因为微软不够开放,没有提供从硬件到应用服务器再到业务应用的整套解决方案。

冷月葬花魂 发表于 2015-2-8 10:03:51

代码的可重用性差:由于是面向结构的编程方式,并且混合html,所以可能页面原型修改一点,整个程序都需要修改,更别提代码重用了。

分手快乐 发表于 2015-2-25 09:04:38

最强的技术支持WebService,而且有.NET的所有library做后盾。而且ASP.NET在.NET3.5中还有微软专门为AJAX开发的功能--ASP.NETAJAX。

山那边是海 发表于 2015-3-7 19:15:50

我觉得什么语言,精通就好,你要做的就是比其他80%的人都厉害,你就能得到只有20%的人才能得到的高薪。

爱飞 发表于 2015-3-15 12:08:07

主流网站开发语言之JSP:JSP和Servlet要放在一起讲,是因为它们都是Sun公司的J2EE(Java2platformEnterpriseEdition)应用体系中的一部分。

谁可相欹 发表于 2015-3-22 01:04:10

可以通过在现有ASP应用程序中逐渐添加ASP.NET功能,随时增强ASP应用程序的功能。ASP.NET是一个已编译的、基于.NET的环境,可以用任何与.NET兼容的语言(包括VisualBasic.NET、C#和JScript.NET.)创作应用程序。另外,任何ASP.NET应用程序都可以使用整个.NETFramework。开发人员可以方便地获得这些技术的优点,其中包括托管的公共语言运行库环境、类型安全、继承等等。
页: [1]
查看完整版本: ASP.NET编程:在.NET中利用定名管道完成历程间通讯