WCF和Remoting之间的消息传输
作者:springsnow 发布时间:2023-04-15 01:01:20
一.NET Remoting 介绍
简介
.NET Remoting与MSMQ不同,它不支持离线可得,另外只适合.NET平台的程序进行通信。它提供了一种允许对象通过应用程序域与另一个对象进行交互的框架。.NET 应用程序都在一个主应用程序域中执行的,在一个应用程序域中的代码不能访问另一个应用程序域的数据,然而在某些情况下,我们需要跨应用程序域,与另外的应用程序域进行通信,这时候就可以采用.NET Remoting技术来实现与另一个程序域中的对象进行交互。
基本原理
.NET Remoting技术是通过通道来实现两个应用程序之间对象的通信的。
首先,客户端通过Remoting技术的访问通道来获得服务器端对象,再通过代理解析为客户端对象,也称作透明代理,此时获得客户端对象只是服务器对象的一个引用。这既保证了客户端和服务端有关对象的松散耦合,同时优化了通信的性能。在这个过程中,当客户端通过透明代理来调用远程对象的方法时,此时会将调用封装到一个消息对象中,该消息对象包括远程对象信息,被调用的方法名和参数,然后透明代理会将调用委托给真实代理(RealProxy对象)的Invoke方法来生成一个IMethodCallMessage,
接着通过序列化把这个消息对象序列化成数据流发送到通道,通道会把数据流传送到服务器端。当服务器接收到经过格式化的数据之后,首先从中通过反序列化来还原消息对象,之后在服务器端来激活远程对象,并调用对应的方法,而方法的返回结果过程则是按照之前的方法反向重复一遍。具体的实现原理图如下所示:
远程对象:
是运行在服务器端的对象,客户端不能直接调用,由于.NET Remoting传递的对象是以引用的方式,因此所传递的远程对象必须继承MarshalByRefObject类,这个类可以使远程对象在.NET Remoting应用通信中使用,支持对象的跨域边界访问。
远程对象的激活方式
在访问服务器端的一个对象实例之前,必须通过一个名为Activation的进程创建它并进行初始化。这种客户端通过通道来创建远程对象的方式称为对象的激活。在.NET Remoting中,远程对象的激活分为两大类:服务器端激活和客户端激活。
1、服务器端激活(WellKnow(知名对象)激活模式)
为什么称为知名对象激活模式呢?是因为服务应用程序在激活对象实例之前会在一个众所周知的统一资源标示符(URI)上发布这个类型,然后该服务器进行会为此类型配置一个WellKnow对象,并根据指定的端口或地址来发布对象。
.NET Remoting把服务器端激活又分为SingleTon模式和SingleCall模式两种。
SingleTon模式:此为有状态模式。.NET Remoting将为所有客户端建立同一个对象实例。服务端只在对象第一次被调用时创建服务对象,当对象处于活动状态时,SingleTon实例会处理所有后来的客户端访问请求,而不管它们是同一个客户端,还是其他客户端。SingleTon实例将在方法调用中一直维护其状态,类似static成员的概念。(相当于Application状态)
SingleCall模式:是一种无状态模式。则当客户端调用远程对象的方法时,Remoting会为每一个客户端建立一个远程对象实例,对象实例的销毁则是由GC自动管理。类似实例成员的概念。(相当于Session状态)
2、客户端激活:
与Wellknow模式不同,。NET Remoting在激活每个对象实例的时候,会给每个客户端激活的类型指派一个URI。客户端激活模式一旦获得客户端的请求,将为每一个客户端都建立一个实例引用。SingleCall模式与客户端激活模式的区别有:
首先,对象实例创建的时间不同。客户端激活方式是客户一旦发出调用请求就实例化,而SingleCall则要等到调用对象方法时再创建。
其次,SingleCall模式激活的对象是无状态的,对象声明周期由GC管理,而客户端激活的对象是有状态的,其生命周期可自定义。
第三,两种激活模式在服务器端和客户端实现的方法不一样,尤其是在客户端,SingleCall模式由GetObject()来激活,它调用对象默认的构造函数,而客户端激活模式,则通过CreateInstance()来激活,它可以传递参数,所以可以调用自定义的构造函数来创建实例。
通道:
在.NET Remoting中时通过通道来实现两个应用程序域之间对象的通信。.NET Remoting中包括4中通道类型:
TcpChannel:Tcp通道使用Tcp协议来跨越.Net Remoting边界来传输序列化的消息流,TcpChannel默认使用二进制格式序列化消息对象,因此具有更高的传输性能,但不提供任何内置的安全功能。
HttpChannel:Http通道使用Http协议在客户端和服务器之间发生消息,使其在Internet上穿越防火墙来传输序列化的消息流。默认情况下,HttpChannel使用Soap格式序列化消息对象,因此它具有更好的互操作性,并且可以使用Http协议中的加密机制来对消息进行加密来保证安全性。因此,通常在局域网内,我们更多地使用TcpChannel,如果要穿越防火墙,则使用HttpChannel。
IpcChannel:进程间通信,只使用同一个系统进程之间的通信,不需要主机名和端口号。而使用Http通道和Tcp通道都要指定主机名和端口号。
自定义通道:自定义的传输通道可以使用任何基本的传输协议来进行通信,如UDP协议、SMTP协议等。
二、服务端激活方式:SAO
1、创建一个共享接口的dll,服务端和客户端都要引用它。
//定义接口类ITax
//编译生成ITaxTemoting.dll
//服务器端和客户端都要添加该类dll的引用
public interface ITax
{
double GetTax(int salary);
}
创建远程对象,该对象必须继承MarshalByRefObject对象。远程对象类Tax继承了基类MarshalByRefObject和接口ITax。
//定义远程对象,必须继承自MarshalByRefObject
//编译生成TaxRemoting.dll,服务器端必须添加该dll的引用
public class Tax : MarshalByRefObject, ITax
{
private int _callOCunt = 0;
public Tax()
{
Console.WriteLine("Remoting object Tax 已激活");
}
//根据税
public double GetTax(int salary)
{
_callOCunt++;
return (double)tax;
}
}
2、服务端
需要添加System.Runtime.Remoting.dll引用
定义通道并监听,注册远程对象。信道用于.NET客户端和服务器端的通信。
在.NET Remoting中,是允许同时创建多个通道的,但是.NET Remoting要求通道的名字必须不同,因为名字是用来标识通道的唯一标识符。
TcpChannel channel = new TcpChannel(8085);//定义通道,还有HttpChannel\IPCChannel等
ChannelServices.RegisterChannel(channel, false);//注册通道
RemotingConfiguration.RegisterWellKnownServiceType(typeof(Tax), "Tax1", WellKnownObjectMode.SingleCall);
//在服务端注册一个知名的远程对象Tax,ObjectURI为Tax,知名对象模式为单次调用方式。
3、客户端
注册信道,根据URL获取远程对象代理,使用代理调用服务器端的远程对象。
void Main()
{
TcpChannel channel = new TcpChannel();
ChannelServices.RegisterChannel(channel, false);
ITax obj = (ITax)Activator.GetObject(typeof(ITax), "tcp://localhost:8085/Tax1");//根据URL获取远程对象代理,使用此代理调用服务端的远程对象。
if (obj == null)
{
Console.WriteLine("Could not locate TCP server");
}
Console.WriteLine(obj.GetTax(1).ToString());//调用远程对象的方法获取结果,此时调用服务端的类的默认构造函数实例化。
Console.WriteLine(obj.GetCallCount().ToString());
Console.WriteLine(obj.GetTax(1).ToString());
Console.WriteLine(obj.GetCallCount().ToString());
}
//也可以先为客户端注册类型,再实例化对象(不推荐)
RemotingConfiguration.RegisterWellKnownClientType(typeof(ITax), "tcp://localhost:8085/Tax1");
Tax obj = new Tax();
obj.GetTax();
三、客户端激活方式:CAO
可以调用服务端非默认的带参数的构造函数,服务端为每个客户端保存不同的状态。
1、声明定义一个公共类
public class Tax : MarshalByRefObject, ITax
{
//代码同服务端SAO
}
2、服务端,应用Tax所在的程序集
TcpChannel channel = new TcpChannel(8085);
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.ApplicationName = "Tax1";
RemotingConfiguration.RegisterActivatedServiceType(typeof(Tax));
3、客户端
可以使用Soapsuds.exe分离Tax程序集共客户端调用(即不包含具体的实现内容)
E:>soapsuds -url:http://127.0.0.1:8502/TaxTax1?wsdl -oa:ClientProxy.dll
这将为我们在E盘的根目录下生成ClientProxy.dll文件,这个文件将用于客户端成生代理。
void Main()
{
TcpChannel channel = new TcpChannel();
ChannelServices.RegisterChannel(channel, false);
Tax obj = (Tax)Activator.CreateInstance(typeof(ITax), null, new[] {new UrlAttribute ("tcp://localhost:8085/Tax1")});//根据URL获取远程对象代理,使用此代理调用服务端的远程对象。
Console.WriteLine(obj.GetTax(1).ToString());
Console.WriteLine(obj.GetCallCount().ToString());
Console.WriteLine(obj.GetTax(1).ToString());
Console.WriteLine(obj.GetCallCount().ToString());
}
//也可以先为客户端注册类型,再实例化对象(不推荐)
RemotingConfiguration.RegisterActivatedClientType(typeof(ITax), "tcp://localhost:8085/Tax1");//Activator.GetObject
Tax obj = new Tax();
obj.GetTax();
4、关闭注销通道
channel.StartListening(null);
ChannelServices.UnregisterChannel(channel);
四、使用配置文件来重写上面的分布式程序
服务端:
RemotingConfiguration.Configure("RemotingServerHostByConfig.exe.config", false);
服务端的配置文件app.config的内容为
<configuration>
<system.runtime.remoting>
<application>
<service> <!--服务端,如果是客户端改成Client –>
<wellknown type="Tax" objectUri="Tax1" mode="SingleCall" /> <!--客户端激活改成activator—>
</service>
<channels>
<channel ref="tcp" port="8085" />
</channels>
</application>
</configuration>
客户端:
RemotingConfiguration.Configure("RemotingClientByConfig.exe.config", false);
客户端配置文件的内容为:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<client>
<wellknown type="Tax" url="tcp://localhost:8085/Tax1" />
</client>
<channels>
<channel ref="tcp" port="8085"></channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
来源:https://www.cnblogs.com/springsnow/p/9434009.html


猜你喜欢
- 前言 短时间提升自己最快的手段就是背面试题,最近总结了Java常用的面试题,分享给大家,希望大家都能圆梦大厂,加油,我命由我不由天
- 1. 导入依赖包// retrofit, 基于Okhttp,考虑到项目中经常会用到retrofit,就导入这个了。 compil
- 安卓系统本身可以很简便的实现分享功能,因为我们只需向startActivity传递一个ACTION_SEND的Intent,系统就为我们弹出
- Java5 在 java.util.concurrent 包中已经包含了读写锁。尽管如此,我们还是应该了解其实现背后的原理。读/写锁的 Ja
- 一、线程池简介线程池的使用主要是解决两个问题:①当执行大量异步任务的时候线程池能够提供更好的性能,在不使用线程池时候,每当需要执行异步任务的
- 一、简介构造函数,基本用法是在类对象声明的时候完成初始化工作。二、实例构造函数1、构造函数的名字与类名相同。2、使用 new 表达式创建类的
- 这里文章写出来并不是为了炫耀什么,只是觉得发现些好东西就分享出来而已,同时也做个记录,方便以后查找开始正文1、先介绍本文会用到的window
- 经测试,是环绕通知改变了返回值,切面方法需要有返回值,来代替被代理方法返回结果改成如下即可:@Around("point_upda
- 归并排序原理1.尽可能的一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组的元素个数是1为止。⒉将相邻的两个子组
- java读取resources文件详解及实现代码Java项目中,经常需要将资源文件打包放在项目中,然后在项目中去读取对应的文件。实现代码:S
- 前言在上篇文章《初识GraphQL》中我们大致的了解了GraphQL作用,并通过简单示例初步体验了GraphQL的使用。下面我们从Hello
- 本文实例讲述了C#在RichTextBox中显示不同颜色文字的方法。分享给大家供大家参考。具体实现方法如下:#region 日志记录、支持其
- 本文实例讲述了C#获取路径的几种方式。分享给大家供大家参考。具体如下:string str1 =Process.GetCurrentProc
- 绑定多个按钮到同一个事件1.添加代码private void clauseElementClicked(object sender, Eve
- 私有构造函数私有构造函数是一种特殊的实例构造函数。它通常用在只包含静态成员的类中。如果类具有一个或多个私有构造函数而没有公共构造函数,则其他
- 1. 定义TreeMap的排序方法使用Comparator对象作为参数需要注意的是:排序方法是针对键的,而不是值的。如果想针对值,需要更麻烦
- 在windows环境下进行的测试,前提条件,windows上需要先安装openssl。配置环境变量,查看版本:import java.io.
- 一、同步问题提出线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏。例如:两个线程ThreadA、ThreadB都操作同一个对
- java中对List分段操作的实例问题:假设A系统查询出来一个很大很大的List,现在B系统想要得到这个List来导出报表,但是B系统部署环
- 故事背景故事发生在几个星期前,自动化平台代码开放给整个测试团队以后,越来越多的同事开始探索平台代码。为了保障自动化测试相关的数据和沉淀能不被