收藏本站 
广告服务 
网站地图 
>> 为你提供近10万篇各类电脑技术文章、网络技术教程、软件技术文章、网页设计教程、平面设计教程、数据库技术教程等方面的电脑教程!
先飞电脑技术网技术文章网络编程ASP.Net
网络编程 | 网站建设 | 网络技术 | 设计教程 | 软件教学 | 程序开发 | 数据库开发 | 教育认证 | 硬件维护 | 媒体动画 | 机械电子 |

用.Net Remoting技术实现定向广播

[ 作者:佚名    转贴自:网络转载    阅读次数:102    更新时间:2007-11-17 11:47:00   录入:刘光勇 ]         
    相对于 WebService 来说,采用 .Net Remoting  技术的客户端能够订阅服务器端事件,这个功能简直太棒了。

  如果想利用该技术作一个简单而又典型的应用,信息广播程序是一个不错的选择。以下代码是一个简单的广播程序,当然,它实在太简陋了。

  服务端:

以下是引用片段:
  Code
  class Program
  {
  static void Main(string[] args)
  {
  BinaryServerFormatterSinkProvider sfsp = new BinaryServerFormatterSinkProvider();
  sfsp.TypeFilterLevel = TypeFilterLevel.Full;
  Hashtable props = new Hashtable();
  props["port"] = 8086;
  TcpChannel channel = new TcpChannel(props, null, sfsp);
  ChannelServices.RegisterChannel(channel, false);
  SayHello sayHello = new SayHello();
  RemotingServices.Marshal(sayHello, "SayHello");
  Console.ReadKey();
  sayHello.Say("Mike", "Hello, Mike");
  Console.ReadKey();
  sayHello.Say("John", "Hello, John");
  Console.ReadKey();
  }
  }

  客户端:

以下是引用片段:
Code
  class Program
  {
  static void Main(string[] args)
  {
  BinaryServerFormatterSinkProvider sfsp = new BinaryServerFormatterSinkProvider();
  sfsp.TypeFilterLevel = TypeFilterLevel.Full;
  Hashtable props = new Hashtable();
  props["port"] = 0;
  TcpChannel channel = new TcpChannel(props, null, sfsp);
  ChannelServices.RegisterChannel(channel, false);
  SayHello sh = (SayHello)Activator.GetObject(typeof(SayHello), "tcp://localhost:8086/SayHello");
  SayEventReappear re = new SayEventReappear();
  re.ClientId = "John";
  sh.OnSay += new SayHandler(re.Say);
  re.OnSay += new SayHandler(re_OnSay);
  Console.ReadKey();
  }
  static void re_OnSay(string text)
  {
  Console.WriteLine(text);
  }
  }

  远程对象、委托及事件重现器(需同时部署在服务端及客户端):

以下是引用片段:
Code
  public class SayHello : MarshalByRefObject
  {
  public event SayHandler OnSay;
  public void Say(string clientId, string text)
  {
  if (this.OnSay != null) this.OnSay(text);
  }
  }
  public delegate void SayHandler(string text);
  public class SayEventReappear : MarshalByRefObject
  {
  public event SayHandler OnSay;
  public void Say(string text)
  {
  if (this.OnSay != null) this.OnSay(text);
  }
  }

  OK,我的信息广播程序就这样完成了。

  但是,我很快就发现了问题:如果我的确想让所有订阅我的广播事件的客户端都得到我要广播的信息,这个实现应该不会有问题。但是现在我有一个消息只想通知 Mike 或 John (正如以上代码),(注:可能这时不能再称为“广播”了),我的广播程序依然将这个消息通知到了每一个客户端。

  考虑到 .Net Remoting 客户端订阅事件的实现原理:事件重现器在客户端实例化,并由服务器对按引用方式对其远程调用(个人理解,未经确认,欢迎指正)。如果将事件重现器订阅服务器端事件改为向服务器端“注册”事件重现器,逻辑上应该可行,这样就可以让每个客户端注册的事件重现器携带自己的客户标识,让服务端根据标识决定是否引发特定客户端的事件。修改后的代码如下:

  远程对象:

以下是引用片段:
Code
  public class SayHello : MarshalByRefObject
  {
  private List reList = new List();
  public void Say(string clientId, string text)
  {
  foreach (SayEventReappear re in this.reList)
  {
  if (re.ClientId == clientId) re.Say(text);
  }
  }
  public void AddEventReappear(SayEventReappear re)
  {
  this.reList.Add(re);
  }
  }

  客户端程序

以下是引用片段:
sh.OnSay += new SayHandler(re.Say);改为 sh.AddEventReappear(re);

  OK,服务端分别检测每一个客户端的Id,然后只引发特定客户端的事件,真正的“定向广播”实现了。

  但是检查一下以上代码,会发现依然存在问题:由于事件重现器的实例存在于客户端,服务端访问的是它的代理类,因此每次对 ClientId 的检查都是一次远程调用,这无疑是一种浪费。因此将程序改为在客户端注册事件重现器时提交 ClientId 或许更合理。修改后的代码如下:

  远程对象:

以下是引用片段:
Code
  public class SayHello : MarshalByRefObject
  {
  private Dictionary reDict = new Dictionary();
  public void Say(string clientId, string text)
  {
  foreach (KeyValuePair kp in this.reDict)
  {
  if (kp.Key == clientId) kp.Value.Say(text);
  }
  }
  public void AddEventReappear(string clientId, SayEventReappear re)
  {
  if (!this.reDict.ContainsKey(clientId)) this.reDict.Add(clientId, re);
  }
  }

  事件重现器:

以下是引用片段:
Code
  public class SayEventReappear : MarshalByRefObject
  {
  public event SayHandler OnSay;
  public void Say(string text)
  {
  if (this.OnSay != null) this.OnSay(text);
  }
  }

  客户端:

以下是引用片段:
 sh.AddEventReappear(re);改为: sh.AddEventReappear("John", re);

  如此一来,不仅避免了对客户端的频繁调用,而且代码也更加简洁了。

  当然,同利用“事件订阅”方式实现时当订阅事件的客户端退出时应该取消订阅一样,该实现中的客户端在退出时同样应该取消在服务端的“注册”。由于只是示例程序,以上代码中并没有进行取消注册处理。

  但是问题恰恰出在这儿了,如果有的客户端没有自觉的取消注册或者意外退出/断线了,服务器端该如何处理呢?当然使用事件订阅时这个问题同样存在,但我估计 .Net Remoting 会根据生命周期原则适时“清除”已订阅事件而不再响应的客户端(同样是个人猜测,没有证实)。如果服务器端将连接失败的客户端直接取消注册,显然是对客户端的一种不负责任(如果客户端因临时资源紧张或临时断线无法及时响应时将被永久取消注册),但除此之外我没有想出合适的办法进行处理,总不能让已经不存在的客户端一直处于注册状态吧?!当然还有一种折中的办法是对客户端连接失败进行计数或计时,达到一定程度后认为客户已经不存在而进行注销。

文章首页【加入到收藏夹】告诉好友】【打印此文】【关闭窗口
  版权声明:本站提供的“用.Net Remoting技术实现定向广播”版权归文章所有者,转载请注明出处!
 ·上一篇文章:ASP.Net编程中实现MD5加密算法      ·下一篇文章:用JScript.net写Asp.Net应用程序
相关文章
·用.Net Remoting技术实现定向广播[102]
·用.Net处理XmlHttp发送异步请求[28]
·使用.NET实现你的IP切换器[19]
·在SQL Server中使用CLR调用.NET方法[14]
·SQL Server中使用CLR调用.NET方法[58]
网站主页 | 收藏本页 | 联系我们 | 广告服务 | 站点地图 | 会员注册 | 隐私政策 | 内容指正

联系QQ:先飞电脑技术网站事务联系QQ,点击可以直接留言. 32933427 电话:13710542091 [世界排名] 鄂ICP备05005890号 先飞电脑教程网