65.9K
CodeProject 正在变化。 阅读更多。
Home

.NET Remoting 消息重定向通道接收器

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.38/5 (20投票s)

2003年6月21日

3分钟阅读

viewsIcon

117857

downloadIcon

1676

一种上层逻辑层透明的方式来重定向 .NET remoting 调用,从而使 .NET remoting 服务能够穿透防火墙/NAT,到达任何地方。

引言

.NET remoting 是一个很棒的框架,但它最严重的缺陷在于阻止其在当今互联网环境中的应用,因为它要求每个节点都拥有一个全局 IP,以便能够建立直接的 TCP 连接。 存在其他针对此问题的未完成解决方案 (GenuineChannel),但它们使用了特殊的传输通道(而不是标准的 TCP/HTTP),其中包含大量未经检验的自定义代码,从而使您的代码变得更重且不稳定。 这些解决方案也不允许两个位于防火墙后的对象互相调用。

Reachability 通道接收器提供了一种更轻量、优雅的解决方案。 通过 *消息重定向器*,可以使用标准传输通道,使得位于防火墙后的仅具有本地 IP 的机器所托管的 remoting 对象可以从任何地方访问(包括这些机器本身位于防火墙之后)。 整个过程对上层逻辑层是透明的。 也支持异步调用和单向调用。

.NET remoting 的优势

.NET remoting 具有以下优势

  • 将网络代码与逻辑代码分离。
  • 优于 WebService:客户端可以从服务器接收事件。可以传递更多类型。更高的吞吐量。

虽然 .NET remoting 旨在满足企业内部网应用程序的需求,但没有任何东西阻止它在 Internet 上使用,至少没有安全问题——它没有安全漏洞——缓冲区溢出在完全用 .NET remoting 框架编写的托管代码中是不可能的。.NET remoting 非常适合点对点应用程序,因为它减轻了程序员编写管理复杂网络拓扑的复杂网络代码的工作。

如何在您的项目中进行使用

配置文件

  • 对于位于防火墙后面并且需要公开主机的对象
    <appSettings>
      <add key="RedirectorURL" 
        value="tcp://Redirector's IP:Port/Redirector.rem" />
    </appSettings>
    ....
       <serverProviders>
         <provider type="Reachability.ServerSinkProvider, Reachability" />
           <formatter ref="binary" />
       </serverProviders>
  • 对于需要通过 Redirector 调用对象的宿主
    <clientProviders>
          <formatter ref="binary" />
            <provider 
             type="Reachability.ClientSinkProvider, Reachability" />
    </clientProviders>
  • 对于 Redirector
    <wellknown mode="Singleton" 
            type="Reachability.Redirector, Reachability" 
        objectUri="Redirector.rem" />
    ...
             <channels>
               <channel ref="tcp" port="Redirector's Port" >
                <serverProviders>
           <formatter ref="binary" />
         </serverProviders>
         <clientProviders>
          <formatter ref="binary" />
         </clientProviders>
        </channel>
        
             </channels>

所需的代码

Reachability.dll 的引用添加到您的项目中。

需要通过 Redirector 公开对象的宿主必须在 RemotingConfiguration.Configure() 之后或 RemotingServices.Marshal() 之后调用 Reachability.ServerSinkProvider.StartWaitRedirectedMsg()。 此调用的效果是开始从 Redirector 接收消息。

工作原理

已经有很多关于 .NET remoting 工作原理和通道接收器的文章,我没有时间在这里重复这些描述。 Reachability 接收器有 3 个组件

  1. Redirector 服务
  2. “服务器”通道接收器
  3. “客户端”通道接收器

基本上,服务器接收器将可达性信息(即,我们可以通过哪个 Redirector 将消息发送到此对象)添加到(ChannelData 中的)ObjRef。 当此 ObjRef 传递到某处时,客户端接收器发现附加到 ObjRef 的可达性信息,并且它不直接尝试连接到该对象,而是将调用传递给 Redirector。 只要创建 ObjRef 的宿主在 Redirector 上正确侦听,Redirector 就会适当地传递调用。(这是通过 StartWaitRedirectedMsg() 完成的)。

这是使防火墙后面的宿主接收调用的代码的核心(无需特殊传输通道)

public void RedirectRequest(Guid slot, bool oneway, 
     ITransportHeaders requestHeaders, byte[] requestStream, 
     out ITransportHeaders responseHeaders, out byte[] responseStream)
{
   SyncQueue q = reqs[slot] as SyncQueue;  
   if(q==null)reqs.Add(slot, q=new SyncQueue());
   q.Enqueue(new Message(requestHeaders, 
       requestStream, Thread.CurrentPrincipal, oneway));
   
   if(!oneway)
   {
      q = resps[slot] as SyncQueue;   
      if(q==null)resps.Add(slot, q=new SyncQueue()); 

      Response r = q.Dequeue() as Response;
      responseHeaders = r.responseHeaders;
      responseStream = r.responseStream;
   }
   else
   {
      responseHeaders = null;
      responseStream = null;
   }
}
.....
   static void WaitForRequest(object o)
   {
      Redirector r = Activator.GetObject(typeof(Reachability.Redirector), 
                     RedirectorUrl) as Reachability.Redirector;
      Redirector.Message m;
      try
      {
         while(true)
         {
            r.GetNextRequest(rdata.Slot, out m);
            if(m==null)break;
          // must place this sink after formatter before
          // server transport, so message goes into stream.
            IMessage respMsg;    

                ITransportHeaders respHeader;
                Stream respStream;
            ServerChannelSinkStack stack = 
                  new ServerChannelSinkStack();     
                stack.Push(new ServerSink(theSink),r);
     
               theSink.ProcessMessage(stack,null,
                 m.requestHeaders,
                 new MemoryStream(m.requestStream),
               out respMsg, out respHeader, out respStream);
               if(!m.oneway)
               {
                    r.ReturnResponse(rdata.Slot, 
              new Redirector.Response(respHeader, respStream));
           }
        }
     }
     catch(Exception e){
        System.Diagnostics.Trace.Write(e.ToString());
     }
   }

防火墙后面的节点不会侦听传入的调用,而是调用 GetNextRequest() 并阻塞,直到传入的调用到达(类似于 Windows API GetMessage())。 Redirector 将被阻塞,直到调用 ReturnResponse()

© . All rights reserved.