一步一步学Remoting之四:承载方式(2)

Demo:截图


这里来说一下iis承载方式,顺便简单说一下remoting的通道和【复杂对象】中的遗留问题。

首先明确一点:iis来承载的话只能是http通道方式的。

我们来建立一个web项目,比如叫remoting,删除项目中的所有webform,把远程对象dll-RemoteObject.dll复制到项目的dll文件夹下面,然后打开web.config进行服务端设置:

<configuration>
    <appSettings>
            <add key="strconn" value="server=(local);uid=sa;pwd=;database=UBISOFT" />
    </appSettings>
    <system.runtime.remoting>
        <application>
            <service>
                <wellknown type="RemoteObject.MyObject,RemoteObject" objectUri="MyObject.soap"
                    mode="SingleCall" />
            </service>   
            <channels>
                <channel ref="http"/>
            </channels>   
        </application>
    </system.runtime.remoting>
</configuration>

来分析一下这个config:
1、可能大家还不是很理解type属性,其实type属性分两部分<命名空间.类名>,<程序集>
2、objectURi是用来表示对象的uri的,到时候我们用这个uri来连接到服务端
3、我们需要为uri指定soap(soap格式化)或者rem(二进制格式化)后缀

要进行测试其实很简单,我们在浏览器输入:http://localhost/remoting/MyObject.soap?wsdl
进行测试,如果发生问题基本就是配置文件的问题或者对象dll没有正确复制到dll目录

接下来修改一下客户端的配置文件就可以了,主要是修改地址。

<configuration>
 <appSettings>
 <add key="ServiceURL" value="http://localhost/remoting/MyObject.soap"/>
 </appSettings>
</configuration>

iis承载方式默认是80端口,我们不需要在端口上做任何设置。还需要注意到的是iis方式,我们使用这样的格式作为地址:
http://ip地址/虚拟目录/远程对象.soap

运行了客户端以后如果我们的数据量比较大的话,就算是本机我们也能感受到延迟,比tcp方式延迟厉害很多很多,其实http方式的remoting效率比webservice还要差,具体选择http方式的remoting还是webservice还是要看我们是不是对对象的状态有需求。

iis的部署也是自动启动服务的,还有一个优点就是可以结合iis的windows身份认证,这个参照一些iis的配置文章,这里就不说了。

下面还是要来看一下两种【通道】:
    默认情况下,HTTP 通道使用 SOAP 格式化程序,因此,如果客户端需要通过 Internet 访问对象,则可以使用 HTTP 通道。由于这种方法使用 HTTP,所以允许客户端通过防火墙远程访问 .NET 对象。将这些对象集成在 IIS 中,即可将其配置为 Web 服务对象。随后,客户端就可以读取这些对象的 WSDL 文件,以便使用 SOAP 与 Remoting 对象通信。
    默认情况下,TCP 通道使用二进制格式化程序。此格式化程序以二进制格式进行数据的序列化,并使用原始套接字在网络中传送数据。如果对象部署在受防火墙保护的封闭环境中,则此方法是理想的选择。该方法使用套接字在对象之间传递二进制数据,因此性能更好。由于它使用 TCP 通道来提供对象,因此具有在封闭环境中开销较小的优点。由于防火墙和配置问题,此方法不能在 Internet 上使用。

因此我们也需要更根据自己的需求来选择通道!看看remoting有这么多可以选择的方式:选择激活模式,选择通道,选择承载方式,如此多的选择给了我们灵活的同时也增加了理解remoting的难度。

msdn相关章节:http://msdn.microsoft.com/library/CHS/cpguide/html/cpconChannels.asp

最后说一下前面的遗留问题,为什么会发生这个安全异常?
http://www.cnblogs.com/lovecherry/archive/2005/05/20/159335.html

msdn说:
依赖于运行时类型验证的远程处理系统必须反序列化一个远程流,然后才能开始使用它,未经授权的客户端可能会试图利用反序列化这一时机。为了免受这种攻击,.NET 远程处理提供了两个自动反序列化级别:Low 和 Full。Low(默认值)防止反序列化攻击的方式是,在反序列化时,只处理与最基本的远程处理功能关联的类型,如自动反序列化远程处理基础结构类型、有限的系统实现类型集和基本的自定义类型集。Full 反序列化级别支持远程处理在所有情况下支持的所有自动反序列化类型。

我们首先来修改服务端的配置文件:

<configuration>
    <system.runtime.remoting>
        <application name="RemoteServer">
            <service>
                <wellknown type="RemoteObject.MyObject,RemoteObject" objectUri="RemoteObject.MyObject"
                    mode="Singleton" />
            </service>
            <channels>
                <channel ref="tcp" port="9999"/>
                <serverProviders>
                    <provider ref="wsdl" />
                    <formatter ref="soap" typeFilterLevel="Full" />
                    <formatter ref="binary" typeFilterLevel="Full" />
                    </serverProviders>
            </channels>
        </application>
    </system.runtime.remoting>
</configuration>

当然也可以用程序进行设置:
using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Serialization.Formatters;
RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemoteObject.MyObject), "RemoteObject.MyObject", WellKnownObjectMode.Singleton);
            BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
            BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();
            serverProvider.TypeFilterLevel = TypeFilterLevel.Full;
            IDictionary props = new Hashtable();
            props["port"] = 9999;
            TcpChannel channel = new TcpChannel(props,clientProvider,serverProvider);
            ChannelServices.RegisterChannel(channel);
            Console.ReadLine();
客户端还要用程序进行调整:
若要使用配置文件设置反序列化级别,必须显式指定 <formatter> 元素的 typeFilterLevel 属性。虽然这通常是在服务器端指定的,但您还必须为注册来侦听回调的客户端上的任何信道指定这一属性,以控制其反序列化级别

在程序前面加上和服务端基本相同的代码:
BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
            BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();
            serverProvider.TypeFilterLevel = TypeFilterLevel.Full;
            IDictionary props = new Hashtable();
            props["port"] = 0;
            TcpChannel channel = new TcpChannel(props,clientProvider,serverProvider);
            ChannelServices.RegisterChannel(channel);
这样就可以了,注意:如果在同一个机器上面测试端口号应设为不同于服务器端设置的端口号,推荐设置为0(远程处理系统自动选择可用端口)

.NET Remoting 自身不提供安全模型。然而,通过将远程对象驻留在 ASP.NET 中并使用 HTTP 通道进行通信,远程对象可以使用 IIS 和 ASP.NET 提供的基本安全服务。比较而言,TCP 通道和自定义的主机可执行文件能够提供更高的性能,但这种组合不提供内置的安全功能。

• 若要对客户端进行身份验证,请使用 HTTP 通道,在 ASP.NET 中驻留对象,以及在 IIS 中禁用匿名访问。
 
• 如果您不担心客户端身份验证问题,请使用 TCP 通道,它可以提供更高的性能。
 
• 如果您使用 TCP 通道,请使用 IPSec 保护客户端和服务器之间的通信通道。使用 SSL 来保护 HTTP 通道。
 
• 如果您需要对远程资源进行受信任的调用,请将组件驻留在 Windows 服务中,而不是驻留在控制台应用程序中。
 
• 始终不要向 Internet 公开远程对象。在这种情况下,请使用 Web 服务。
应该仅在 Intranet 中使用 .NET Remoting。应该使用内部方式从 Web 应用程序访问对象。即使对象驻留在 ASP.NET 中,也不要向 Internet 客户端公开它们,因为客户端必须是 .NET 客户端。

最后,让我们来看一篇msdn有关remoting安全的文章:
http://www.microsoft.com/china/msdn/library/architecture/architecture/architecturetopic/BuildSucApp/BSAAsecmod11.mspx
说到这里大家可能对remoting的一些基本知识稍微优点概念了,后续文章会继续不断强化这些概念!

就我所知,目前在Server端似乎还没有办法为WellknownServiceObject选择其使用的信道。.NET Remoting的通信信道的选择,好像是由底层自己进行的。而且Server端注册的ObjectUri,只是一个不完整路径,例如"Test",而在Client端使用的时候,则是完整Url路径:tcp://localhost:8086/Test。
 
  我所测试的代码里,通过Client激活对象时所指定的URL,可以选择远程通信所用的信道的类型。这主要通过其协议"tcp://"和端口"8086"来确定。
 
  也就是说,以下例子中,我们在服务器端注册的TestClass对象,无法确定其在tcp信道上还是在http信道上。一切都是根据客户端的具体请求来选择。 

共享测试类如下:
namespace Share
{
    public class TestClass : MarshalByRefObject
    {
        public string Hello()
        {
            return "Hello from remoting!";
        }
    }
}

Server端使用这个配置文件,分别注册了一个tcp信道,一个http信道。远程对象只注册了一个用于测试的类。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.runtime.remoting>
    <application>
      <channels>
        <channel name="Channel1" port="8086" ref="tcp"/>
        <channel name="Channel2" port="8088" ref="http"/>
      </channels>
      <service>
        <wellknown mode="Singleton" type="Share.TestClass, Share" objectUri="Test"/>
      </service>
    </application>
  </system.runtime.remoting>
</configuration>

Server 代码:
RemotingConfiguration.Configure( "Server.exe.Config" );
Client端也注册了两个信道,tcp的和http的,配置如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.runtime.remoting>
    <application>
      <channels>
        <channel name="Channel1" port="8186" ref="tcp"/>
        <channel name="Channel2" port="8188" ref="http"/>
      </channels>
    </application>
  </system.runtime.remoting>
</configuration>
 
Client代码:
RemotingConfiguration.Configure( "Client.exe.Config" );
Share.TestClass test1 = (Share.TestClass) Activator.GetObject(
    typeof( Share.TestClass ), "tcp://localhost:8086/Test" );
Share.TestClass test2 = (Share.TestClass) Activator.GetObject(
    typeof( Share.TestClass ), "http://localhost:8088/Test" );
Console.WriteLine( test1.Hello() );
Console.WriteLine( test2.Hello() );
原文地址:https://www.cnblogs.com/Leo_wl/p/1733055.html