wcf的客户端意外退出,服务器崩溃我用wcf写了一个聊天室,用的tcp协议连接的, 现在是如果有一个客户端意外退
wcf的客户端意外退出,服务器崩溃
我用wcf写了一个聊天室,用的tcp协议连接的, 现在是如果有一个客户端意外退出以后,这个信道会死掉。
然后客户端无法再登陆,提示信道错误。任何一个人也都无法连接使用,必须重新把服务器退出然后再启动。
1.请问大家有什么好的办法能及时知道客户端意外断线了。
2.服务器端如何扫描所有的信道,检查哪个信道阻塞了,已经无法使用的然后再删除掉(意思是,服务器端是否可以向这个通道发送一个包,根据这个包的状态判断这个信道是否正常)
3.我登陆的客户端都是保存在服务器端的 list表里面, 客户端直接取不出来这个list 请教如何返回这个。
[最优解释]
1. duplex的话,可以加上Channel.Closing事件监听。
OperationContext.Current.Channel.Closing += new EventHandler(Channel_Closing);
http://blog.csdn.net/fangxinggood/archive/2011/01/15/6142861.aspx
2. 应该让客户端发送心跳给服务端,服务端检查是否活动链接。
3. 不明白客户端想要什么。
参考:
http://topic.csdn.net/u/20110304/14/705fc930-3e17-4e04-81ee-d56b15162c33.html
[其他解释]
当时是不会,但是有inactivityTimeout啊,超时的时候还是会触发这个事件的。
[其他解释]
把你的 WCF 服务好好描述下,比如:ServiceBehavior的InstanceMode, 用到Duplex了吗?
[其他解释]
看这文章,不过好像也没有结果:
http://www.cnblogs.com/Jax/archive/2009/02/11/1388076.html
[其他解释]
看了看,有个bug的:
if (!_callback.Contains(guest))
{
_callback.Remove(guest);
_userinfo.Remove(strGuest);
}
退出后,仍然会通知一个已经退出的客户端。
但这应该不是问题关键。看了配置文件,没有inactivityTimeout的配置。
是否和这有关?
[其他解释]
查了下msdn:
通道上的活动定义为接收应用程序或基础结构消息。 非活动超时属性会控制保持非活动会话存在的最长时间。 如果超过 InactivityTimeout 指定的时间间隔后仍没有活动,则基础结构会中止会话,且通道会出错。 可靠会话会遭到单方面撤销。
如果发送应用程序没有要发送的消息,则可靠会话通常不会因处于非活动状态而出错,“保持活动状态”机制会让会话无限期地处于活动状态。 请注意,如果未发送或接收任何应用程序消息,则调度程序可以单独中止可靠会话。 因此,如果网络状况为未收到任何类型的消息或发送方失败,则非活动超时通常会过期。
设置此超时可防止服务器在客户端关闭安全会话之前一直保持该会话。 如果安全会话在非活动时间间隔内未收到消息,则服务器会将其关闭。 这样可降低发生拒绝服务攻击的可能性。
使用可靠会话时,必须同时满足两个不同的非活动计时器,才能使连接处于活动状态。 如果任一非活动计时器结束计时,则将断开连接。
第一个非活动计时器为可靠会话计时器,称为 InactivityTimeout。 如果在超时期限内没有收到任何应用程序消息或基础结构消息,此非活动计时器将激发。 基础结构消息是指为了通道堆栈中的协议之一(例如,保持活动状态或确认,而并非包含应用程序数据)而生成的消息。
第二个非活动计时器为服务计时器,它使用绑定的 ReceiveTimeout 设置。 如果在超时期限内没有收到任何应用程序消息,此非活动计时器将激发。
由于任一非活动计时器激发都会断开连接,因此单纯增大 InactivityTimeout(当其大于 ReceiveTimeout 时)不起任何作用。 这两个超时时间的默认值均为 10 分钟,因此在使用可靠会话时,必须同时增大这两个超时时间才会起作用。
还有个 ReceiveTimeout 也应该设置。
[其他解释]
第2个客户端貌似dead lock了。你把他的 JoinRoom 改为 OneWay 试下。我觉得这种callback的,不应该这么用。
[其他解释]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
配置为多线程,即使一个出错也不至于影响其它客户端登录。
[其他解释]我试了这个示例,都改为oneway,去掉UserInfo() 还没有出现你说的问题。
在另一台机器上断开网络,服务也没有死掉。而且,等待半分钟再接入网络,还可以正常通信。
(这说明,duplex默认有超时时间判断)
客户端显示的 client.Close() 会触发 Channel.Closeing和Closed事件。
如果有需要,留下你的mail,我把修改后的例子给你发过去。
[其他解释]该回复于2011-03-08 16:19:44被版主删除
------其他解决方案--------------------
楼上的那个哥们,客户端如果是网线突然中断的话,服务器是不会收到这个反馈消息的
[其他解释]我很郁闷一件事情,为什么一个channel 坏掉了,所有的客户都无法登陆使用了。是不是换成异步能解决这个问题。或者需要换成别的模式?
inactivityTimeout好像不起作用,一旦通道被阻塞以后,无论等多久,都不会自动清除这个。心跳包 比如是30秒发一次,而在第20秒的时候,恰好一个通道阻塞了,这个时候都会死掉。遇见这样的问题如何解决?
[其他解释]比如:
[其他解释] [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]//这个我换了三种模式得到的结果都是一样的
public class Service1:ichat
{
//客户端登陆
public void jionRoom(string userName)
{
ichatcallback callback = OperationContext.Current.GetCallbackChannel<ichatcallback>();
if (_callback.Contains(callback)==false)
{
_userinfo.Add(userName, callback);
_callback.Add(callback);
_callback.ForEach(delegate(ichatcallback callbackmy) { callbackmy.notifyJoinRoom(userName); });
}
}
}
我测试是这样的,本地上先打开一个一个客户端登陆,然后强行非法退出,然后再打开一个客户端登陆,提示错误报告错误是下面这个结果。
System.ServiceModel.CommunicationObjectFaultedException: 通信对象 System.ServiceModel.Channels.ServiceChannel 无法用于通信,因为其处于“出错”状态。
[其他解释]刚才更郁闷了,客户端在同一个电脑打开多个都没有问题,但是一个客户端在另外一个电脑上登陆就会报错跟上面的一样。 是不是因为我这个登陆是用的同步 ,所以会错误
[其他解释]我的这个例子是按照 http://blog.csdn.net/fuyicheng1212/archive/2009/09/01/4509098.aspx 这个朋友写的教程写的,但是我下载了他的例子运行,发现问题一样,如果不正常退出,会发生通道阻塞,任何一个客户端都访问不成了死掉了
[其他解释]InactivityTimeout 这个如果要配置上的话,肯定是需要客户端一直往服务器端发送心跳包保持连接了。
//客户端登陆
public void jionRoom(string userName)
{
ichatcallback callback = OperationContext.Current.GetCallbackChannel<ichatcallback>();
if (_callback.Contains(callback)==false)
{
_userinfo.Add(userName, callback);
_callback.Add(callback);
_callback.ForEach(delegate(ichatcallback callbackmy) { callbackmy.notifyJoinRoom(userName); });
}
}
}
这一段是不是存在问题,如果客户端在同一个电脑上登陆没有问题,但是位于两个不同的电脑,第二个客户端一运行这个就会死掉了
[其他解释]所有的函数我都是用的oneway ,你觉得应该如何写比较好。避免一个客户端死了,别的客户端也无法响应
[其他解释]哥们意思是没开一个客户端都是重新用一个线程对吧,我一会去试一下。
[其他解释]哥们我找到问题的原因了,是因为list添加重复信息报错,我已经修改过了。现在不死了,我也在客户端添加了心跳包机制,每隔10秒更新服务器的列表,但是有一个情况比如客户端a往客户端b发送一个消息的时候,如果b已经突然停电断线,但是服务器是间隔一个时间才会更新错误然后删除这个b,正好在这个间隔时间内的话。客户端a发送的包到b被阻塞,然后这个a也会出现channel错误,心跳包也无法发送给服务器,过一会a也会被服务器超时连接给清除了。如果两个人正在频繁聊天的时候,这个情况很容易发生。 如果遇见这个情况,如何服务器能有一个判断【发送到b的channel出现错误】,然后停止a往b的消息发送,然后清除b的通道,以免a通道跟着一起出错。
[其他解释]bu hao
[其他解释]哥们是这样的,如果3个客户端,a,b,c 如果a死掉了,b和c是可以互相通信的,但是如果b往a发送消息,因为a的通道已经错误了,所以b这个时候发送消息同样也会被阻塞了。结果b也错误了。 就是现在有什么办法,客户端判断a信道已经错误的时候,就不再给它发送消息了而是保存成一个离线消息在服务器端,避免自己也死了的可能性。
客户端a如果是正常退出的我可以从list表里面删除掉不会出错,但是a断电了,这个地方希望能有一个办法判断一下
我的邮箱是xiaottyy@163.com 非常感谢你了
[其他解释]悲剧啊
[其他解释]给你mail了。
[其他解释]null
[其他解释]很有有收获!!