在 Remoting 中使用 Event 主要是为了实现 CallBack 机制,让服务器在接收到某个 "消息" 时,主动调用某个或多个客户端的方法。
我们先看一个例子。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace Learn.Library.Remoting
{
/// <summary>
/// 委托类型
/// </summary>
public delegate void TestHandler();
/// <summary>
/// 远程类型
/// </summary>
public class Data : MarshalByRefObject
{
public TestHandler OnTest;
public void Test()
{
Console.WriteLine("Test...(AppDomain:{0})", AppDomain.CurrentDomain.FriendlyName);
if (OnTest != null) OnTest();
}
}
public class RemotingTest2
{
/// <summary>
/// 服务器端代码
/// </summary>
static void Server()
{
AppDomain server = AppDomain.CreateDomain("server");
server.DoCallBack(delegate
{
BinaryServerFormatterSinkProvider bin = new BinaryServerFormatterSinkProvider();
bin.TypeFilterLevel = TypeFilterLevel.Full;
TcpServerChannel channel = new TcpServerChannel("server", 801, bin);
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(Data), "data",
WellKnownObjectMode.Singleton);
});
}
/// <summary>
/// 客户端代码
/// </summary>
static void Client()
{
TcpClientChannel channel = new TcpClientChannel();
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.RegisterWellKnownClientType(typeof(Data), "tcp://localhost:801/data");
Data data = new Data();
data.OnTest += delegate
{
Console.WriteLine("OnTest...(AppDomain:{0})", AppDomain.CurrentDomain.FriendlyName);
};
data.Test();
}
static void Main()
{
Server();
Client();
}
}
}
输出:
Test...(AppDomain:server)
OnTest...(AppDomain:server)
运行结果表明客户端事件方法 OnTest 被顺利执行。只不过结果有点问题,OnTest 是在服务器程序域内执行,这显然和我们设想服务器去通知客户端有所出入。这种方式实质上是将客户端委托方法一起序列化为消息传递到服务器端,然后在服务器应用程序域被执行,因此客户端是无法接收到所谓 "回调消息" 的。
要实现我们所需要的 Remoting Event,需要做如下步骤:
1. 采取所谓 Duplex 方式。也就是说在客户端和服务器同时启用 ServerChannel 和 ClientChannel,因此我们需要使用 HttpChannel 或 TcpChannel。
2. 客户端事件方法应该是一个继承自 MarshalByRefObject 类型的实例方法。因为服务器是通过创建客户端的 MBR SAO 对象来实现回调的。
3. 缺省情况下,Delegate 无法被序列化,因此我们需要将服务器的 Formatter.TypeFilterLevel 设置为 Full。
修改后的代码。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace Learn.Library.Remoting
{
/// <summary>
/// 委托类型
/// </summary>
public delegate void TestHandler();
/// <summary>
/// 远程类型
/// </summary>
public class Data : MarshalByRefObject
{
public TestHandler OnTest;
public void Test()
{
Console.WriteLine("Test...(AppDomain:{0})", AppDomain.CurrentDomain.FriendlyName);
if (OnTest != null) OnTest();
}
}
/// <summary>
/// 客户端远程类型
/// </summary>
public class ClientData : MarshalByRefObject
{
public void OnTestMethod()
{
Console.WriteLine("Test...(AppDomain:{0})", AppDomain.CurrentDomain.FriendlyName);
}
}
public class RemotingTest2
{
/// <summary>
/// 服务器端代码
/// </summary>
static void Server()
{
AppDomain server = AppDomain.CreateDomain("server");
server.DoCallBack(delegate
{
BinaryClientFormatterSinkProvider cbin = new BinaryClientFormatterSinkProvider();
BinaryServerFormatterSinkProvider sbin = new BinaryServerFormatterSinkProvider();
sbin.TypeFilterLevel = TypeFilterLevel.Full;
Hashtable properties = new Hashtable();
properties["port"] = 801;
TcpChannel channel = new TcpChannel(properties, cbin, sbin);
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(Data), "data",
WellKnownObjectMode.Singleton);
});
}
/// <summary>
/// 客户端代码
/// </summary>
static void Client()
{
TcpChannel channel = new TcpChannel(802);
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.RegisterWellKnownClientType(typeof(Data), "tcp://localhost:801/data");
Data data = new Data();
data.OnTest += new ClientData().OnTestMethod;
data.Test();
}
static void Main()
{
Server();
Client();
}
}
}
输出:
Test...(AppDomain:server)
Test...(AppDomain:Test.exe)
分享到:
相关推荐
Remoting事件(服务端广播改进).
Microsoft .Net Remoting系列专题之三:Remoting事件处理全接触
C# Remoting 断网事件处理+聊天系统
在Remoting中处理事件其实并不复杂,但其中有些技巧需要你去挖掘出来。正是这些技巧,仿佛森严的壁垒,让许多人望而生畏,或者是不知所谓,最后放弃了事件在Remoting的使用。关于这个主题,在网上也有很多讨论,相关...
是.net Remoting事件的简单例子,学习为主.
对Remoting 事件不了解的朋友,就从这里开始吧。看过以后会感受不少哦
使用.NET Remoting从服务器主动发出事件通知客户端(远程广播) 经常看见有人问:使用.NET Remoting如何从服务器主动发出事件通知客户端?的确,初接触.NET Remoting的人多半会有这样的疑问,因为大部分的文章和...
前言:在Remoting中处理事件其实并不复杂,但其中有些技巧需要你去挖掘出来。正是这些技巧,仿佛森严的壁垒,让许多人望而生畏,或者是不知所谓,最后放弃了事件在Remoting的使用。关于这个主题,在网上也有很多讨论...
Remoting事件(服务端广播)
remoting技术
Remoting事件示例代码: 客户端发送传真
Remoting事件(服务端广播)
实现了tcp协议下的remoting事件注册。
Jenkins remoting 是一个可执行的 JAR,它在自动化服务器中实现通信层。 它用于主 <=> 代理和主 <=> CLI 通信。 通常,该库包含引导程序代码,用于将单独的 JVM 桥接到单个半共享空间中。 它包括:基于 TCP ...
Remoting技术服务器,调用客户端事件
Microsoft .Net Remoting系列专题之三:Remoting事件处理全接触
Remoting 经典例子(服务器 客户端 相互调用实例),我就是学这个入门的,资源共享
Remoting事件(服务端广播改进)https://blog.csdn.net/cao919/article/details/118539963
C# .Net Remoting 两个简单示例,一个为普通的,一个为工厂模式的,更为安全一点.简单范例却是打好了一个框架,想要做东西,扩展就可以了. 使用说明和运行截图:http://www.our-code.com/news/2010105/n4920152.html 关于2...
remoting分布式技术入门教程,不可多得