首先我们需要了解为什么需要构建分布式应用程序
•客户端仅需较少硬件支持,共享高效的服务器硬件
•在客户端仅仅部署少量组件,因此易于应用程序更新
•易于监视应用程序,备份数据
•服务器为安全提供了额外的层面
那么也就可以在分布式应用程序中,计算的主力实在服务端,而客户端主要是用于呈现和操作数据的,并且,由于数据在服务端,我们可以很容易的监视应用程序及其数据
分布式设计分为两类
1.同步:客户端调用,阻塞等待响应。也就是说,我们客户端的应用程序必须等待服务端响应请求之后才能继续往下执行。
2.异步:客户端发送请求,并且继续执行。也就是说客户端应用程序发送请求之后不会等待服务端响应之后才继续向下执行,而是边执行自己的代码,边等待服务端的响应。
异步设计可以给用户更好的体验,如果用同步设计,发送请求之后,如果服务端很忙,那么客户端就好像已经死了一样,不能动掸,异步有更好的灵活性,但是它的实现和测试比较困难。同步设计比较简单,它基于传统的编程模型,调用方法-等待调用返回成功-继续执行。
RPC(Remote Procedure Call)远程方法调用,主要利用代理的设计模式,在客户端有一个代理的类,通过代理的类通讯调用服务端对应的类。
这一课主要讲解了.Net Remoting、WebService、WebApp三种同步设计
1..Net Remoting:应用程序进行调用,等待专用数据返回,这种方式是效率最高的方式。用于连接在相同平台(.NET)上运行的
不同机器
2.WebService:应用程序发出请求,等待XML数据。因为返回的是XML数据,那么这种方式是跨平台的。用于连接在不同平台上运行的应用程序
3.WebApp:浏览器请求页面,等待HTML数据。GUI是与平台无关的。用于平台无关的GUI解决方案
使用.net Remoting的动机:通常用于连接应用程序的不同层次由于使用专用数据格式以及自定义网络协议,因此有着更高的效率,但是客户端和服务器都需要安装.net平台。
要使用.net Remoting,我们只需要写类库的时候像正常的一样,但是必须继承MarshalByRefObject类,为了对象能够保持在服务端,并且客户端能够维持对象引用
- public class Calculator : MarshalByRefObject
- {
- private int callCount;
- public Calculator()
- {
- callCount = 0;
- }
- public int Add(int x, int y, int delayInSecs, out string info)
- {
- int pid, tid, result;
- string machine;
- callCount++;
- Thread.Sleep(delayInSecs + 1000);
- result = x + y;
- //得到进程ID
- pid = Process.GetCurrentProcess().Id;
- //得到线程ID
- tid = Thread.CurrentThread.ManagedThreadId;
- //机器名
- machine = System.Environment.MachineName;
- info = string.Format("Running on {0}: pid={1}, tid={2}, callCount={3}",
- machine, pid, tid, callCount);
- return result;
- }
- }
在编写好这个dll之后,我们需要新建一个WebService网站,并且将此dll引入到此网站中。然后在webconfig的configuration配置节中添加下面的配置
- <system.runtime.remoting>
- <application>
- <service>
- <wellknown mode="SingleCall" objectUri="Calculator.rem" type="CalculatorComponent.Calculator, CalculatorComponent"></wellknown>
- </service>
- </application>
- </system.runtime.remoting>
在这个配置节上,我们使用了mode="SingleCall",并且指定了url地址,注意后缀名必须是rem或soap,前缀名可以任意。在配置好这个配置节之后我们来创建一个winform应用程序来调用.net Remoting。
我们先制作这样一个窗体,再来看代码
- public partial class Form1 : Form
- {
- //声明计算类
- private CalculatorComponent.Calculator calc;
- public Form1()
- {
- InitializeComponent();
- }
- private void button1_Click(object sender, EventArgs e)
- {
- int x, y, delay, result;
- string info;
- x = int.Parse(textBox1.Text);
- y = int.Parse(textBox2.Text);
- delay = progressBar1.Value;
- //直接调用对象的方法
- result = calc.Add(x, y, delay, out info);
- textBox3.Text = result.ToString();
- listBox1.Items.Insert(0, info);
- }
- private void Form1_Load(object sender, EventArgs e)
- {
- //注册已知的客户端类型,注意,后面的url地址必须与webconfig配置的objectUri值一样。
- RemotingConfiguration.RegisterWellKnownClientType(Type.GetType("CalculatorComponent.Calculator, CalculatorComponent"), "http://localhost:41479/CalculatorServer/Calculator1.rem");
- //实例化类
- calc = new CalculatorComponent.Calculator();
- }
- }
OK,当我们点击Calculator的按钮的时候,我们发现计算值已经返回过来了。这种方式是使用Host.dll在Web Server中,这种方式的好处是可以穿透防火墙,因为是使用http协议的。在上面的代码执行中,我们发现callCount的值总是1,那是因为我们使用mode="SingleCall",我们使用这种方式的时候,每次调用在服务器端会新生成一个对象,所以每次都是1。
single-call MBRO:每个RPC结果都返回在服务器端上的新的Calculator对象,不需要维持状态,每次生成新的对象。
服务器端对象也能够被“MBVO”:序列化并且物理移动到客户端(代码和数据),数据量交互太大,需要维持状态。
如何维持状态?
•服务器端保存到数据存储
•服务器端从数据存储获取状态
•服务器端返回具有状态的对象给客户端— MBVO!
除了SingleCall这种无状态的方式还有Activated和Singleton方式, Activated表示每个客户端只有一个对象, Singleton表示全局只有一个对象。
WebSerive用于连接不同的应用程序,从不同平台上的应用程序访问数据。在WebService中WSDL(Web Service Description Language)来制定数据的标准,WebService的代码示例这里就不提供了。
WebService与Remoting几乎等价,是多线程,无状态,可扩展的,但是客户端不需要必须运行.net,并且开发的设计选项比较少,是MBDO(marshal by data only),也就是说只对数据(公共区域)marshal,而不涉及到代码。
最后就是WebForm,与平台无关的GUI,这个对asp.net开发人员是简单的,不在这里详述。