.Net Remoting的双向通信和Windows Service的宿主服务

原文:.Net Remoting的双向通信和Windows Service的宿主服务

作为微软分布式技术之一的.Net Remoting,从性能、安全等各方面来说都是相对比较稳定的,也是一项比较成熟的分布式技术。

从学习.Net Remoting至今,仅仅只使用了一次这门技术,是在去年的一个IM产品中。最近公司的产品出现了很多问题,服务器、通信接口、网站都陆续被攻击(DDOS)。这对于做互联网产业的同行来说就清楚这里面的关系,强大的DDOS攻击可以直接让产品无法正常运营甚至停止运营。

经过一系列的分析,我打算使用.Net Remoting这门技术人为的通过编程开发的方式来解决上述的一些问题。其中.Net Remoting的双向通信机制可以解决产品中的部门业务流程(比如在线充值,充值成功|失败通知客户端),从通信效率上来说也优于WEB应用接口(比如Alipay的支付接口)。基于Windows Service的宿主服务、或通过IIS来宿主Remoting的服务都是比较方便的。不过我放弃了基于IIS部署.Net Remoting,IIS部署的服务始终都无法逃避开DDOS的攻击。 Windows Service相比之下更适合于防止DDOS攻击。

现在有一个小的功能需求,我们要做一个聊天应用,要求使用.Net Remoting来提供远程接口,当客户端调用.Net Remoting远程接口发送消息到服务器后,服务器对详细进行一系列的处理(如在多人聊天的情况下广播消息,一对一聊天的情况下传递消息到另一客户端,其中还可能包括写数据库等多项操作),这里为了方便演示我就将消息回发给自己。

好的,了解清楚了需求我们可以定义两个接口,一个应用于发送消息的接口,一个应用于回发消息的接口,从某种角度(如WCF中)也可以叫契约。

1 namespace ChatRoom.Contract
 2 {
 3     public interface IDuplexChat
 4     {
 5         void SendMessage(string message, IChatCallback callBack);
 6     }
 7 }
 8 namespace ChatRoom.Contract
 9 {
10     /// <summary>
11     /// 服务器端回调接口
12     /// </summary>
13     public interface IChatCallback
14     {
15         /// <summary>
16         /// 回调方法,显示聊天消息
17         /// </summary>
18         /// <param name="message"></param>
19         void ShowMessage(string message);
20     }
21 }

接口定义好了,现在可以提供Remoting远程服务了,既然是.Net Remoting远程服务,那么就必须继承于MarshalByRefObject,同时我们还实现IDuplexChat接口,如下:

1 namespace ChatRoom.Remoting
 2 {
 3     public class DuplexChatRemoting : MarshalByRefObject, IDuplexChat
 4     {
 5         public void SendMessage(string message, IChatCallback callBack)
 6         {
 7             Console.WriteLine("Invoke the method SendMessage()");
 8 
 9             //do other
10             callBack.ShowMessage(message);
11         }
12     }
13 }

通常开发.Net Remoting程序都会有宿主、服务和客户端三个基本的程序模块。上面已经实现了Remoting服务,接下来就需要将该服务通过一种特定的方式来宿主(控制台程序、IIS或Windows Service)服务,宿主服务也就是将远程服务公布出来,并提供一种远程连接的方式,通常也称其为通道(信道)。鉴于程序的灵活性我们可通过配置文件的方式来配置.Net Remoting,比如我们通过控制台程序来宿主服务,如下配置代码块:

1 <?xml version="1.0" encoding="utf-8" ?>
 2 <configuration>
 3   <system.runtime.remoting>
 4     <application name="ChatRoom">
 5       <service>
 6         <wellknown mode="SingleCall" type="ChatRoom.Remoting.DuplexChatRemoting,ChatRoom.Remoting" objectUri="ChatRoomURL"></wellknown>
 7       </service>
 8       <channels>
 9         <channel ref="http" port="8080">
10           <serverProviders>
11             <provider ref="wsdl"></provider>
12             <formatter ref="binary" typeFilterLevel="Full"></formatter>
13           </serverProviders>
14           <clientProviders>
15             <formatter ref="binary"></formatter>
16           </clientProviders>
17         </channel>
18       </channels>
19     </application>
20   </system.runtime.remoting>
21 </configuration>

1 namespace ChatRoom.ConsoleHost
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             RemotingConfiguration.Configure("ChatRoom.ConsoleHost.exe.config", false);
 8             Console.WriteLine(".Net Remoting 服务已启动");
 9             Console.Read();
10         }
11     }
12 }

宿主和服务都提供好,现在我们需要一个调用客户端,远程服务已经通过宿主提供好了并定义好了通信信道。那么客户端也得遵守宿主里提供的通信规则,既按照宿主里提供的通信地址和端口进行通信。

Code
 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <configuration>
 3   <system.runtime.remoting>
 4     <application>
 5       <channels>
 6         <channel ref="http" port="0">
 7           <serverProviders>
 8             <provider ref="wsdl"></provider>
 9             <formatter ref="binary" typeFilterLevel="Full"></formatter>
10           </serverProviders>
11           <clientProviders>
12             <formatter ref="binary"></formatter>
13           </clientProviders>
14         </channel>
15       </channels>
16     </application>
17   </system.runtime.remoting>
18 </configuration>

客户端的调用示例程序代码块:

1 namespace ChatRoom.Client
 2 {
 3     class Program
 4     {
 5         static IDuplexChat proxy = null;
 6         static string message = string.Empty;
 7 
 8         static void Main(string[] args)
 9         {
10             RemotingConfiguration.Configure("ChatRoom.Client.exe.config", false);
11             proxy  = (IDuplexChat)Activator.GetObject(typeof(IDuplexChat), "http://localhost:8080/ChatRoom/ChatRoomURL");
12 
13             message = Console.ReadLine();
14             SendMessage(message);
15         }
16 
17         private static void SendMessage(string message)
18         {
19             proxy.SendMessage(message, new ChatRoomCallBackHandler());
20 
21             message = Console.ReadLine();
22             if (message != "exit")
23             {
24                 SendMessage(message);
25             }
26         }
27     }
28 }

OK,如上便可完成一个双向通信(Client---Server|Server---Client)的简单应用。通过上面使用控制台的方式来宿主.Net Remoting的远程服务,如果不小心关闭了控制台也就管理了远程服务,每次使用远程服务都需要先确保服务已经成功启动,这是非常麻烦的事情。

我们可以通过Windows服务来避免不小心关闭远程服务的缺点,建立Windows服务项目,直接将上面控制台程序里的配置文件复制到Windows服务项目里,在默认的Server1的代码文件下装载.Net Remoting服务就OK:

1 protected override void OnStart(string[] args)
2 {
3     RemotingConfiguration.Configure("ChatRoom.WinServiceHost.exe.config", false);
4 }

光这样是不能完成Windows服务的开安并成功安装,还需要一个安装程序类来对Windows服务进行一些设置。详细请查询Windows服务开发相关的资料。

最后只需要将windows服务安装到计算机上就OK。

本文示例代码下载:ChatRoom.rar

版权说明

本文属原创文章,欢迎转载,其版权归作者和博客园共有。

作      者:Beniao

文章出处:http://beniao.cnblogs.com/  或  http://www.cnblogs.com/

原文地址:https://www.cnblogs.com/lonelyxmas/p/9906519.html

时间: 2024-10-02 03:06:44

.Net Remoting的双向通信和Windows Service的宿主服务的相关文章

windows service自动重启服务

服务一般都能正常的运行,但有时候也会有一些假死现象,比如公司有一考勤服务就因为依赖于硬件厂家的api, 但厂家api运行一段时间后会默名的假死,引起整个服务假死,因为这一假死现象具有不确定性,所以不太可能 看到假死后手动去进行启动. 目前本人知道的有两种方法解决这种情况: 1.写另一个服务,对此当前服务进行监听[需要一些共同数据来判断是否为假死],一但发现假死,进行重新启动2.利用服务本身进行重启. a.打开 控制面板->管理工具->服务,找到需要自动重启服务,点击右键->属性,点击 恢

springboot打包jar文件注册成windows service

首先,准备好maven打包好的springboot的jar文件 1.先从git上(https://github.com/kohsuke/winsw/releases)下载图中标出的文件 2. 新建一个xml文件,配置服务注册信息,写入以下内容: <?xml version="1.0" encoding="UTF-8"?> <service> <!--服务ID--> <id>Unique windows service

windows Service 之调试过程(附加到进程里调试,而且启动时间不能超过30秒)

最近第一次用C#写了一个windows service ,其实实现的内容比较简单.就是启动remoting 连接,但是调试相对初次写windws service 的我来说,比较烦.没有经验,而且没办法像调试其他windows 程序一样设置断点,无法看到运行过程.经过查看一些相关资料后,有了一点点调试的心得.特此留笔,以待今后使用. 相关源码: static void Main()        {            ServiceBase[] ServicesToRun; // 同一进程中可

Windows service wrapper 初探

Windows 服务包装器(Windows service wrapper),用于把.exe文件注册为windows服务.比如把Nginx.exe注册为windows服务,这样做的好处是,每次启动nginx时不用在命令行中输入命令,而且可以随windows系统启动而启动.不用担心服务器意外重启,服务挂掉. github地址:https://github.com/kohsuke/winsw 下载地址:https://github.com/kohsuke/winsw/releases 目前(2017

C# Windows Service中执行死循环轮询

用C#编写Windows Service时,执行轮询一般有两种方式,一种是用Timer,System.Timers或者是System.Thread下的,这种执行是按时间循环执行,缺点是也许上个执行还没有完成,又开始执行新的. 另一种方式是利用线程,在OnStart里单开一个线程去跑含有死循环结构的函数,这种方式的缺点是,对线程的控制困难,停止服务了,线程还有可能在执行,不过 .Net 4.0+ 给我们提供了 CancellationTokenSource,用来取消正在运行的线程(Task),代码

管理员控制Windows Service

C# 以管理员方式启动Winform,进而使用管理员控制Windows Service 问题起因: 1,) 问题自动分析Windows服务在正常运行时,确实会存在程序及人为原因导致该服务停止.为了在应用程序使用时确保该服务正常运行,于是有了该讨论主题. 2,)一般账户(尽管是管理员组账户)使用c#代码启动服务,依然会抛出异常,因为当前程序启动账户级别并不是管理员级别. 以管理员启动应用程序解决方案及测试: 为了解决程序以管理员组角色启动应用程序,我们需要在应用程序的工程中添加一个“Applica

在Windows Service 2012上安装IIS 8.0 IIS 6

我的目的是在服务器上安装IIS6 ,但是受到这边文章的启发和按照他的步骤,看到了"IIS 6管理兼容性",我的问题就决解了,我这里是因为要安装vss 2005 和u8等比较早期的软件才会遇到这个问题: 下面内容转载自:http://www.zhaomu.com/news/detail-394.html 内容如下: Windows 2012及其自带的IIS 8.0是微软公司新一代的Web服务器软件,和老版本的IIS相比,有很多破天荒的新功能.随着微软宣布不再支持Windows XP操作系

C# 创建Windows Service

当我们需要一个程序长期运行,但是不需要界面显示时可以考虑使用Windows Service来实现.这篇博客将简单介绍一下如何创建一个Windows Service,安装/卸载Windows Service. 新建Windows Service项目: 删除自动生成的Service1.cs文件,新建WindowsService类,继承ServiceBase. class WindowsService : ServiceBase { public WindowsService() { this.Ser

Windows Service 之 详解

一.Windows 服务简介 Windows 服务是可以在系统启动时自动打开的(不需要任何人登录计算机)的程序. 1.适合创建Windows 服务的场景: [1] 在没有用户交互操作的情况下运行程序: [2] 在权限比交互式用户更大的用户下运行程序: 2.Windows 服务的示例: [1] WCF宿主(假定由于某些原因不能使用IIS): [2] 缓存网络服务器中数据的程序: [3]在后台重新组织本地磁盘数据的程序. 3.Windows 服务的管理: windows系统下:控制面板 → 系统和安