您好
也许这看起来很荒谬,但这至少对我来说是个问题
我写了双工WCF服务,在我的服务中我需要获得活动客户端服务并保存它们,当发生特殊事件时,我调用特定客户端并为其发送一些值。所以我定义字典并保存客户端。 (使用此方法客户端调用)
public static Dictionary<int, IServiceCallbak> ActiveClients;
public void IConnect(int SenderId)
{
if (ActiveClients == null)
ActiveClients = new Dictionary<int, IServiceCallbak>();
Client = OperationContext.Current.GetCallbackChannel<IServiceCallbak>();
if (ActiveClients.Count(ac => ac.Key == SenderId) > 0)
ActiveClients.Remove(SenderId);
ActiveClients.Add(SenderId, Client);
}
那么当我需要从该词典中找到客户端并调用特定方法时:Client.DoSomthing().
此外,当客户端想要退出时,它会调用IDisconnect
方法,该方法将从字典中删除客户端。
But there is problem in client for managing themselves
在app.config
服务连接中定义的一段时间后,将关闭,您应该续订该服务,然后打开该服务。
所以在这种情况下:
1)是否有任何解决方案可以在客户端重新创建并打开服务对象automatically
2)或者当服务端需要调用客户端时,检查该字典中的client-service-object状态,并从服务器端重新打开连接(Ridiculous-solution
)
我认为更好的解决方案是处理Suggestion 1
,我不知道如何!!!
所以现在问题是:Is way exist to do Suggestion 1 Or not?
以前我在评论中描述建议1:
“并自动引用此案例的事件(如关闭或中止),但我在Service-Client中找不到任何相关内容”
答案 0 :(得分:4)
为了防止服务器端关闭连接,您可以在合同中设置Heartbeat()方法,客户端可以定期调用该方法。然而,这并不理想,因为底层套接字可能会掉线,这无法解决这个问题。
就你的建议而言1)如果你在客户端继承ClientBase,那么在你调用一个路由到服务的方法之前,你可能会遇到一个问题。您必须在try / catch中包装调用,然后使用一些重新连接逻辑:
public class MyClass : ClientBase<IContract>, IContract
{
public void ServiceMethod(String data) {
try {
base.Channel.ServiceMethod(data);
}
catch (CommunicationException ce) {
// Perform some reconnect logic here
base.Channel.ServiceMethod(data);
}
}
}
您对建议的评论2)是正确的,如果服务器端和客户端之间有任何防火墙,他们很可能不允许连接
编辑: 为了扩展我对1)的建议,当使用CommunicationException调用服务失败时,您需要创建一个新连接。最简单的方法是在构造函数中创建服务通道,然后在调用失败时创建另一个:
class ServiceClient {
Service1Client mService; // Class generated by VS tool
public ServiceClient()
: base() {
mService = new Service1Client();
}
#region IService1 Members
public string GetData(int value) {
CommunicationState state = mService.State;
if (state == CommunicationState.Closed || state == CommunicationState.Faulted) {
mService = new Service1Client();
}
try {
// Note: The state checked above may not be accurate,
// hence the try...catch
return mService.GetData(value);
}
catch (CommunicationException) {
mService = new Service1Client(); // Reconnect logic
return mService.GetData(value); // If it fails again we are out of luck...
}
}
#endregion
}
EDIT2:
在WCF中,会话由客户端处理,如果客户端和服务之间的会话丢失,我知道无法从客户端或服务恢复该会话。不幸的是,你被困在这里。
如果服务想要通过回调发送破坏的会话,简单地说,它不能。由于网络的工作方式,服务可能不知道实际的客户端地址。这个和其他各种问题(如防火墙)意味着尝试从服务重新建立与客户端的连接是不切实际的。该服务的唯一方法是存储它想要发送给客户端的数据,并在服务检测到客户端已重新连接时发送它。
无法保证客户端将知道底层套接字丢弃,直到客户端尝试通过套接字发送内容,因此try ... catch。一旦知道连接断开,从客户端重新创建频道是我知道处理问题的唯一方法;这是代码示例的作用。
心跳想法是一种主动处理断开连接的方法。它的效率取决于您对检测断开连接所需的速度以及存在多少客户端的要求。连接的客户端越多,心跳就越长,以免您在服务网络上加载负载。
EDIT3:
经过一些额外的挖掘后,可能有办法自动完成你想做的事情。您可以创建所谓的Reliable Session。激活此操作涉及在配置中创建其他条目:
<netTcpBinding>
<binding>
<reliableSession ordered="Boolean"
inactivityTimeout="TimeSpan"
enabled="Boolean" />
</binding>
</netTcpBinding>
它也可用于与Http相关的绑定,请查看有关该功能的Microsoft文档的链接。