高分求:remoting事件断网处理……(顶者有分,问题解决,另开贴送分)

micher_yan 2007-04-05 11:50:58
我在用remoting事件的时候,碰到断网的问题,异常苦恼……
首先看下面的代码:
foreach (Delegate del in BroadCastEvent.GetInvocationList())
{
try
{
tempEvent = (BroadCastEventHandler)del;
tempEvent(info);
}
catch
{
MessageBox.Show("事件订阅者" + index.ToString() + "发生错误,系统将取消事件订阅!");
BroadCastEvent -= tempEvent;
}
index++;
}
}
这个没有任何问题,在单机测试的时候,事件肯定能从广播列表中删除,现在我的问题来了:当客户端突然断网(停电,关机等),服务器端就会长期处在try环节,当一个客户端断网以后,排在他后面的客户端要很长一段时间(大概30-90秒)才能收到消息,而且当下一次消息触发的时候,在try环节同样会等待很长时间。
【重要】这说明一点:就是在上一次try的时候,并没有删除这个客户端的注册……
但是我在单机测试的时候,却没有发现类似的问题,无论怎么关闭客户端,“BroadCastEvent -= tempEvent”都能起作用,当在网络中的时候,客户端异常断开(尤其是在停电时,网络异常中断)这句就不灵了,根本没有把客户端注册的事件删除呀,异常苦恼中……
这个问题早在半年前我就发现了,但是一直解决不了……
...全文
821 点赞 收藏 44
写回复
44 条回复
liangsongjun 2010年11月16日
好久没上网了,对不起大家了。
To levinknight(Coral):你说的方法并不可行,你提出的最后6条有问题,有点自相矛盾哦,clientA已经断电,那么clientA自然就不会调用ProcessObjectDisconnected方法了(第5),更谈不上clientA通过服务器通知别的客户端clientA已经断线(第6)!!
而且您貌似没有提到remoting的事件机制。

我查了很长时间,现在全国都在问这个问题,remoting事件机制在断网的时候通道的关闭是个硬伤,等后续的Net版本有可能能解决,目前有老外的第三方控件解决这个问题,老外的控件叫Belikov.GenuineChannels,可以参考http://www.genuinechannels.com,基本原理是通过手动维护通讯列表来实现的,后台持续监视链接状态,当有客户端异常断开(停电等),则服务器不再往指定客户端广播消息了。


楼上人在江湖飘你说的Net版本是哪个版本啊?
回复 点赞
micher_yan 2007年12月08日
跟踪一下:Remoting的这个问题,持续解决不了,从程序的稳定性出发,Remoting已经被我们项目组否定了,在后续开发中将使用队列(MQ)传递消息,哎,郁闷啊,Remoting开发的效率是队列望尘莫及的。
回复 点赞
micher_yan 2007年06月01日
问题解决,结帐了!
回复 点赞
micher_yan 2007年05月31日
好久没上网了,对不起大家了。
To levinknight(Coral):你说的方法并不可行,你提出的最后6条有问题,有点自相矛盾哦,clientA已经断电,那么clientA自然就不会调用ProcessObjectDisconnected方法了(第5),更谈不上clientA通过服务器通知别的客户端clientA已经断线(第6)!!
而且您貌似没有提到remoting的事件机制。

我查了很长时间,现在全国都在问这个问题,remoting事件机制在断网的时候通道的关闭是个硬伤,等后续的Net版本有可能能解决,目前有老外的第三方控件解决这个问题,老外的控件叫Belikov.GenuineChannels,可以参考http://www.genuinechannels.com,基本原理是通过手动维护通讯列表来实现的,后台持续监视链接状态,当有客户端异常断开(停电等),则服务器不再往指定客户端广播消息了。
回复 点赞
XMUMEEameng 2007年05月17日
遇到和楼主一样的问题,学习楼上的楼上
回复 点赞
zmacro 2007年05月15日
jf
回复 点赞
levinknight 2007年05月15日
解决了说一声音啊,记得给分
回复 点赞
levinknight 2007年05月15日
ITrackingHandler
ITrackingHandler在MSDN中的解释是:指示实现对象必须得到由远程结构发出的有关对象与代理的封送处理、取消封送处理和断开的通知。
该接口有三个方法分别为:

/// <summary>
/// 通知当前实例某个对象已与其代理断开连接。
/// </summary>
/// <param name="obj">obj: 已断开连接的对象。</param>
void DisconnectedObject( object obj )

/// <summary>
/// 通知当前实例已将对象取消封送。
/// </summary>
/// <param name="obj">已封送的对象</param>
/// <param name="or">System.Runtime.Remoting.ObjRef,它由封送处理产生,并表示指定的对象。 </param>
void UnmarshaledObject( object obj, ObjRef or )

/// <summary>
/// 通知当前实例已封送对象
/// </summary>
/// <param name="obj">已取消封送的对象。</param>
/// <param name="or">表示指定对象的 System.Runtime.Remoting.ObjRef。 </param>
void MarshaledObject( object obj, ObjRef or )

今天我们就实现ITrackingHandler接口来解决以下场景应用:

clientA和clientB同时连接到serverA上,这时由于网络原因或断电故障,clientA退出了,但在clientB上却还显示clientA还在线,
那么我们怎样才能帮clientB纠正这个错误呢?答案就是利用ITrackingHandler接口,请看:

首先定义一个接口IRemotingObjectDisconnected

// <summary>
/// 定义一个远程对象在与代理断开连接时需要进行相关处理的接口
/// </summary>
public interface IRemotingObjectDisconnected
{
/// <summary>
/// 处理远程对象销毁
/// </summary>
void ProcessObjectDisconnected();
}

接着实现ITrackingHandler接口, Tracker

/// <summary>
/// 实现一个远程对象的跟踪处理类
/// </summary>
public class Tracker : ITrackingHandler
{
#region Constructors
/// <summary>
/// 构造
/// </summary>
public Tracker(){}
#endregion

#region ITrackingHandler 成员
/// <summary>
/// 通知当前实例某个对象已与其代理断开连接
/// </summary>
/// <param name="obj"></param>
public void DisconnectedObject( object obj )
{
//如果远程对象obj实现了IRemotingObjectDisconnected接口,则让其处理断开连接
if ( obj is Interfaces.IRemotingObjectDisconnected )
( obj as Interfaces.IRemotingObjectDisconnected ).ProcessObjectDisconnected();
}
/// <summary>
/// 通知当前实例已将对象取消封送。
/// </summary>
/// <param name="obj"></param>
/// <param name="or"></param>
public void UnmarshaledObject(object obj, ObjRef or)
{
}
/// <summary>
/// 通知当前实例已封送对象
/// </summary>
/// <param name="obj"></param>
/// <param name="or"></param>
public void MarshaledObject(object obj, ObjRef or)
{
}
#endregion
}
然后在Client中实现IRemotingObjectDisconnected接口,部分代码如下

public class Client: System.MarshalByRefObject, IRemotingObjectDisconnected
{
//.

#region IRemotingObjectDisconnected 成员
/// <summary>
/// 处理 Client 的非正常退出
/// </summary>
public void ProcessObjectDisconnected()
{
//处理退出事件
this.Logout();
}
#endregion
}

至此大部分工作已完成了,接下来在服务器端我们将自定义的tracker跟踪处理程序注册到 System.Runtime.Remoting.Services.TrackingServices。
//注册自定义的跟踪处理程序
System.Runtime.Remoting.Services.TrackingServices.RegisterTrackingHandler( new RemotingObjects.Tracker() );

这样便可以了。

我们再来看看它们是如何工作起来的。

1:注册自定义跟踪处理程序.
2:发布远程对象( Client ).
3:客户端登录服务器获取对象 (生成clientA或clientB......).
4:clientA断电,clientA的租约到期,但由于clientA断电缘故,Sponsor没办法续约租约.
5:自定义的跟踪处理tracker跟踪到clientA已经与代理断开,由于clientA已经实现IRemotingObjectDisconnected接口,
遂调用clientA的ProcessObjectDisconnected方法.
6:clientA通过服务器通知clientB,clientA已断线.

回复 点赞
mqmmx 2007年05月14日
对remoting不是很了解

.net2.0 里有System.Runtime.Remoting.Messaging.OneWay可能有用
回复 点赞
levinknight 2007年05月08日
ConnectionMonitor,用这个,在新的SCSF里。
回复 点赞
hiwjh20021758 2007年05月03日
d
回复 点赞
bingchener 2007年05月02日
帮顶下
回复 点赞
sh_city 2007年05月01日
回复 点赞
simonezhlx 2007年04月29日
还没太看明白,但觉得在catch里做的事情通常都要等,效率不高
回复 点赞
simonezhlx 2007年04月29日
顶完再看
回复 点赞
LeadWorld 2007年04月28日
不会,帮顶
回复 点赞
xingxing2378 2007年04月28日
顶有分啊?
回复 点赞
qingbo_hu 2007年04月28日
帮顶
回复 点赞
zhulei2008 2007年04月27日
不熟,帮顶
回复 点赞
yanhao0708 2007年04月27日
不会,帮顶
回复 点赞
发动态
发帖子
.NET Framework
创建于2007-09-28

1.6w+

社区成员

2.4w+

社区内容

.NET技术 .NET Framework
社区公告
暂无公告