问题描述
嗨
也许这看起来很荒谬,但这至少对我来说是个问题
Hi
Maybe this look like ridiculous but this is problem at least for me
我编写了双工 WCF 服务,在我的服务中,我需要获取活动的客户端服务并保存它们,当发生特殊事件时,我会调用特定的客户端并为其发送一些值.所以我定义了字典并将客户端保存在其中.(用这个方法客户端调用)
I wrote duplex WCF service, in my service I need to get active client service and save them, and when with occurred special event I call specific client and send some values for it. So I define dictionary and save client in that. (With this method client calls)
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
方法,该方法将从字典中删除客户端.
So then when I need find client from that dictionary and call specific method : Client.DoSomthing().
Also when Client wants to exit, it calls IDisconnect
method which will remove client from dictionary.
但是客户端自己管理有问题
在 app.config
中定义的一段时间后,服务连接将关闭,您应该更新它,然后打开该服务.
But there is problem in client for managing themselves
After a period time which define in app.config
service connection will be closed and you should renew that and then open the service.
所以在这种情况下:
1)是否有任何解决方案可以在客户端自动
重新创建和打开服务对象.
2)或者在服务器端,当服务想要调用客户端时,从该字典中检查客户端服务对象的状态,并从服务器端重新打开连接(Ridiculous-solution
)
So in this case:
1)Is there any solution for recreate and open the service object automatically
in client.
2)Or when in server side when service want call clients, check state of client-service-object from that dictionary, and reopen connection from server-side (Ridiculous-solution
)
我认为更好的解决方案是处理建议 1
,我不知道如何!!!.
所以现在的问题是:是否存在执行建议 1 的方法?
之前我在评论中描述了建议 1:
并自动引用此案例的事件(如关闭或中止),但我在服务客户端中找不到任何用于执行此操作的内容"
I think better solution is to handle Suggestion 1
, I don't know how!!!.
So for now the question is: Is way exist to do Suggestion 1 Or not?
Previously I describe Suggestion 1 in Comment:
"And automatically refer to event for this case(like closing or aborting), but I don't find anything for doing this in Service-Client"
推荐答案
为了防止服务器端关闭连接,您可以在合约中设置一个 Heartbeat() 方法,客户端可以定期调用该方法.然而,这并不理想,一方面是因为底层套接字可能会丢失,而这无济于事.
In order to prevent the server side from closing the connection you could set up a Heartbeat() method in the contract that the client could call periodically. This is not ideal however, for one thing because the underlying socket could drop and this does nothing to remedy that.
就您的建议 1) 而言,如果在客户端,您是从 ClientBase 继承的,那么在您调用路由到服务的方法之前,可能不会给出任何问题指示.您必须将调用包装在 try/catch 中,然后使用一些重新连接逻辑:
As far as your suggestion 1) if on the client side you are inheriting from ClientBase you are somewhat stuck in that no indication of a problem may be given until you call a method to route to the service. You would have to wrap the call in a try / catch and then employ some reconnect logic:
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) 的评论是正确的,如果服务器端和客户端之间有任何防火墙,他们很可能不允许连接
Your comment for suggestion 2) is correct, if there are any firewalls between the server side and client they would most likely not allow the connection
为了扩展我对 1) 的建议,当对服务的调用失败并出现 CommunicationException 时,您需要创建一个新连接.最简单的方法是在构造函数中创建服务通道,然后在调用失败时创建另一个:
To expand on my suggestion for 1), you would need to create a new connection when the call to the service fails with a CommunicationException. The simplest approach would be to create the service channel in the constructor and then create another when the call fails:
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
}
编辑 2:
在 WCF 中,会话由客户端处理,如果客户端和服务之间的会话丢失,我知道无法从客户端或服务恢复该会话.不幸的是,你被困在这里了.
In WCF the session is handled by the client, if the session between the client and the service is lost, I know of no way to restore that session, either from the client or the service. You are, unfortunately, stuck here.
如果服务想通过回调发送会话中断,简单地说,它不能.由于网络的工作方式,服务可能不知道实际的客户端地址.这和其他各种问题(如防火墙)意味着尝试从服务重新建立与客户端的连接是不切实际的.服务的唯一方法是存储它想要发送给客户端的数据,并在服务检测到客户端重新连接时发送.
If the service wants to send via the callback with a broken session, simply put, it can't. Because of the way networks work the service may not know the actual client address. This and various other issues (like firewalls) mean that trying to reestablish a connection to the client from the service just isn't practical. The only approach for the service is to store what data it wanted to send to the client and send it when the service detects that the client has reconnected.
不能保证客户端会知道底层套接字正在丢弃,直到客户端尝试通过套接字发送一些东西,因此 try...catch.一旦意识到连接断开,从客户端重新创建通道是我所知道的处理该问题的唯一方法;这就是代码示例所做的.
There is no guarantee that the client will know of the underlying socket dropping, until the client tries to send something over the socket, hence the try...catch. Recreating the channel from the client once it becomes aware of a broken connection is the only way I know of to handle the issue; which is what the code example does.
心跳的想法是一种主动处理断开连接的方法.它的效率取决于您对检测断开连接所需的速度以及存在的客户端数量的要求.连接的客户端越多,心跳的时间就越长,这样您就不会在网络上为服务增加负载.
The heartbeat idea is a way to proactively deal with broken connection. Its efficiency depends on your requirements as to how fast you need to detect a broken connection and how many clients are present. The more clients connected the longer the heartbeat would have to be so that you don't put a load on the network at the service.
编辑 3:
经过一些额外的挖掘后,可能有一种方法可以自动执行您想要的操作.您可以创建所谓的可靠会话.激活它需要在配置中创建额外的条目:
After some additional digging there may be a way to do what you want automatically. You can create what is known as a Reliable Session. Activating this involves creating additional entries in the config:
<netTcpBinding>
<binding>
<reliableSession ordered="Boolean"
inactivityTimeout="TimeSpan"
enabled="Boolean" />
</binding>
</netTcpBinding>
它也可用于与 Http 相关的绑定,请查看有关该功能的 Microsoft 文档的链接.
It is also available for Http related bindings, check out the link to the Microsoft documentation on the feature.
这篇关于Wcf 双工:检索客户端连接?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!