vRemoting——开源高性能仿Remoting远程交互组件(上)
·〉组件简介
(下载链接在文章后面)
在企业软件的建设中,不乏碰到点对点连接,从最初的“数据库直连”,到所谓的“三层架构”。用过 WCF,用过 Remoting。都觉得它们不错。毕竟是微软自家的东西,抽象程度很高,配置性很强。但在使用的过程中难免碰到许多问题,无论是连接产生的问题还是配置产生的问题,总是令人烦不胜烦。比如 Remoting,在使用人数比较多的情况下竟然会很慢?WCF是不是发生无法连接。当然,这可能是由于自身并没有研究透这些东西,也没仔细去追究问题的根本。了解Sofire.vRemoting组件,至少可以让您更明白远程交互的原理。
我喜欢研究。两年来琢磨了很多东西,比如 MSIL、WindowsDesigner和WebKit,这三个都是比较偏门的东西。话题扯远了,从性能上来说,我感觉会比 Remoting 和 WCF 快,因为我采用了大量缓存和 MSIL。但也只是凭感觉,实际上我并没有做测试(最新我做了测试,速度比 Remoting 快 1/3,有兴趣的朋友可以试试)。我唯一做的测试是开了一万条线程,连接服务器。因网络饱和,而出现了5次错误。其余的全部测试成功(每个测试2个连接和4-8 个调用)。
整个代码非常精简,注释也完全到位,并且支持配置文件。前后我花了一个礼拜多的时间。犹豫了一下,将 vRemoting 作为 SOFIRE 套件开源的第一季产品。
以下是解决方案简图(红框处):
·〉服务端演示
新建一个项目,【vRemotingTest.Comm】,这是一个公共类库,可用于服务端和客户端。
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace vRemotingTest.Comm
- {
- public interface IService
- {
- int Sum(int a, int b);
- int Sum(params int[] values);
- string ToUpper(string str);
- void MakeStringUpperCase(ref string str);
- void MakeStringLowerCase(string str, out string lowerCaseString);
- void CalculateArea(ref Rectangle rectangle);
- void Square(long a, out long b);
- string Version1 { get; }
- string Version2 { get; set; }
- }
- [Serializable]
- public class Rectangle
- {
- private int _width;
- private int _height;
- private int _area;
- public Rectangle(int height, int width)
- {
- _height = height;
- _width = width;
- _area = -1;
- }
- public int Area
- {
- get { return _area; }
- set { _area = value; }
- }
- public int Height
- {
- get { return _height; }
- }
- public int Width
- {
- get { return _width; }
- }
- }
- }
从上面的声明来看,服务契约包与普通 Remoting 或 WCF 的契约是一致的。比较引人关注的是,有部分方法包含了 ref 和 out 参数。这也证明了,vRemoting是支持 ref 和 out 参数的。vRemoting 支持:this索引器、属性、方法。可惜不包括事件,远程交互对事件的处理是一件非常麻烦的事情,我有了一点思路,但目前还没找到一个较为完整的方案。所以事件并不支持。但这并不妨碍vRemoting做双向交互。
新建一个项目,【vRemotingTest.Server】,这是测试的服务端。
建立服务契约的实现:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using vRemotingTest.Comm;
- namespace vRemotingTest.Server
- {
- public class ServiceImpl : IService
- {
- #region IService
- public int Sum(int a, int b)
- {
- return a + b;
- }
- public int Sum(params int[] values)
- {
- int sum = 0;
- foreach(int value in values)
- sum += value;
- return sum;
- }
- public string ToUpper(string str)
- {
- return str.ToUpper();
- }
- public void MakeStringUpperCase(ref string str)
- {
- str = str.ToUpper();
- }
- public void MakeStringLowerCase(string str, out string lowerCaseString)
- {
- lowerCaseString = str.ToLower();
- }
- public void CalculateArea(ref Rectangle rectangle)
- {
- rectangle.Area = rectangle.Width * rectangle.Height;
- }
- public void Square(long a, out long b)
- {
- b = a * a;
- }
- public string Version1
- {
- get { return "Version1"; }
- }
- private string _Version2;
- public string Version2
- {
- get
- {
- return this._Version2;
- }
- set
- {
- this._Version2 = value;
- }
- }
- #endregion
- }
- }
紧接着是配置文件【DefaultSetting.xml】:
- <?xmlversion="1.0"encoding="utf-8" ?>
- <ApplicationName=""
- ReturnsError="True">
- <!-- tcp://localhost:8000/One/HelloService.v -->
- <HostName="One"
- ReturnsError="True"
- Port="8000">
- <ServiceName="HelloService"
- ReturnsError="True"
- InstanceMode="Default"
- Contract="vRemotingTest.Comm.IService, vRemotingTest.Comm"
- Type="vRemotingTest.Server.ServiceImpl, vRemotingTest.Server"/>
- </Host>
- </Application>
从配置文件可以看出,配置并不复杂。Application 表示一个“服务应用程序”,一个服务应用程序包含 N 个服务主机,每个服务主机包含N个服务。
服务端的最后一步(只放出部分代码,其余代码见下载示例):
- static void Main(string[] args)
- {
- try
- {
- RemotingApplication.Initialization("DefaultSetting.xml");
- }
- catch(Exception e)
- {
- Console.WriteLine(e);
- Console.ReadLine();
- return;
- }
- RemotingApplication.ApplicationOpening += new EventHandler(RemotingApplication_ApplicationOpening);
- RemotingApplication.ApplicationOpened += new EventHandler(RemotingApplication_ApplicationOpened);
- RemotingApplication.ApplicationClosing += new EventHandler(RemotingApplication_ApplicationClosing);
- RemotingApplication.ApplicationClosed += new EventHandler(RemotingApplication_ApplicationClosed);
- RemotingApplication.ServerOpening += new EventHandler(RemotingApplication_ServerOpening);
- RemotingApplication.ServerOpened += new EventHandler(RemotingApplication_ServerOpened);
- RemotingApplication.ServerFailed += new ExceptionEventHandler(RemotingApplication_ServerFailed);
- RemotingApplication.ServerClosing += new EventHandler(RemotingApplication_ServerClosing);
- RemotingApplication.ServerClosed += new EventHandler(RemotingApplication_ServerClosed);
- RemotingApplication.ClientJoined += new EventHandler(RemotingApplication_ClientJoined);
- RemotingApplication.ClientFailed += new ClientFailedEventHandler(RemotingApplication_ClientFailed);
- RemotingApplication.ClientQuitted += new EventHandler(RemotingApplication_ClientQuitted);
- RemotingApplication.Open();
- Console.ReadLine();
- RemotingApplication.Close();
- }
好了,至此,服务端顺利完成。
·〉客户端演示
相较于服务端,客户端较为简单,只需要简单几步便可以与契约服务进行交互。
新建一个项目,【vRemotingTest.Client】,代码仅仅如下:
- static void Main(string[] args)
- {
- ProxyFactory.Register<IService>("tcp://localhost:8000/One/HelloService.v");
- Console.WriteLine("Press enter continue..");
- Console.ReadLine();
- IService client = ProxyFactory.Create<IService>();
- Console.WriteLine(client.Sum(2, 3));
- Console.WriteLine(client.Sum(2, 3, 4, 5, 6, 7, 8, 9));
- Console.WriteLine(client.ToUpper("this string used to be lower case"));
- string str = "this was a lower case string";
- client.MakeStringUpperCase(ref str);
- Console.WriteLine(str);
- string lowerCaseString;
- client.MakeStringLowerCase("THIS WAS AN UPPER CASE STRING", out lowerCaseString);
- Console.WriteLine(lowerCaseString);
- Rectangle rect = new Rectangle(30, 40);
- Console.WriteLine(String.Format("Area before call : {0}", rect.Area));
- client.CalculateArea(ref rect);
- Console.WriteLine(String.Format("Area after call : {0}", rect.Area));
- long b;
- client.Square(123, out b);
- Console.WriteLine(string.Format("123 squared is {0}", b));
- ((IDisposable)client).Dispose();
- Console.WriteLine("...................................");
- Console.WriteLine("Test Completed...");
- Console.ReadLine();
- }
·〉结束语
至此,服务端与客户端的配置完成。整个过程我刻意将代码量增多,在实际使用过程中,关于 vRemoting 的配置也仅此而已。来看看测试结果吧:
开源是一种分享,如果有人喜欢,或者希望了解原理篇,请推荐一下:),下载地址。