我有两个在同一网络上运行的自托管服务。第一个是对excel表(或其他来源,但目前这是我用来测试的那个)和发送更新到订阅客户端的样本。 第二个作为客户端连接到第一个客户端的实例,可选地评估这些输入上的一些公式,并以与第一个客户端相同的方式将原件或结果广播为订阅客户端的更新。所有这一切都发生在tcp绑定上。
当第二个服务尝试同时订阅两个第一个服务的订阅源时,我的问题就出现了,就像新计算第一次使用两个或更多个时一样。当订阅第二个订阅源时,我一直收到似乎正在发生的TimeoutExceptions。我在第一台服务器上的被调用方法中放置了一个断点并逐步执行它,它能够完全完成并返回true备份调用堆栈,这表明问题可能是WCF的一些烦人的错综复杂
第一个服务在端口8081上运行,这是被调用的方法:
public virtual bool Subscribe(int fid)
{
try
{
if (fid > -1 && _fieldNames.LeftContains(fid))
{
String sessionID = OperationContext.Current.SessionId;
Action<Object, IUpdate> toSub = MakeSend(OperationContext.Current.GetCallbackChannel<ISubClient>(), sessionID);//Make a callback to the client's callback method to send the updates
if (!_callbackList.ContainsKey(fid))
_callbackList.Add(fid, new Dictionary<String, Action<Object, IUpdate>>());
_callbackList[fid][sessionID] = toSub;//add the callback method to the list of callback methods to call when this feed is updated
String field = GetItem(fid);//get the current stored value of that field
CheckChanged(fid, field);//add or update field, usually returns a bool if the value has changed but also updates the last value reference, used here to ensure there is a value to send
FireOne(toSub, this, MakeUpdate(fid, field));//sends an update so the subscribing service will have a first value
return true;
}
return false;
}
catch (Exception e)
{
Log(e);//report any errors before returning a failure
return false;
}
}
第二个服务在端口8082上运行,并且在此方法中失败:
public int AddCalculation(string name, string input)
{
try
{
Calculation calc;
try
{
calc = new Calculation(_fieldNames, input, name);//Perform slow creation before locking - better wasted one thread than several blocked ones
}
catch (FormatException e)
{
throw Fault.MakeCalculationFault(e.Message);
}
lock (_calculations)
{
int id = nextID();
foreach (int fid in calc.Dependencies)
{
if (!_calculations.ContainsKey(fid))
{
lock (_fieldTracker)
{
DataRow row = _fieldTracker.Rows.Find(fid);
int uses = (int)(row[Uses]) + 1;//update uses of that feed
try
{
if (uses == 1){//if this is the first use of this field
SubServiceClient service = _services[(int)row[ServiceID]];//get the stored connection (as client) to that service
service.Subscribe((int)row[ServiceField]);//Failing here, but only on second call and not if subscribed to each seperately
}
}
catch (TimeoutException e)
{
Log(e);
throw Fault.MakeOperationFault(FaultType.NoItemFound, "Service could not be found");//can't be caught, if this timed out then outer connection timed out
}
_fieldTracker.Rows.Find(fid)[Uses] = uses;
}
}
}
return id;
}
}
catch (FormatException f)
{
Log(f.Message);
throw Fault.MakeOperationFault(FaultType.InvalidInput, f.Message);
}
}
这些端口可以更改,但永远不会共享。使用的tcp绑定在代码中使用以下设置进行设置:
_tcpbinding = new NetTcpBinding();
_tcpbinding.PortSharingEnabled = false;
_tcpbinding.Security.Mode = SecurityMode.None;
这是一个公共库,以确保它们都具有相同的设置,这也是它在代码中声明的原因。
我已经尝试更改服务限制行为以获得更多并发调用,但这并不起作用。它现在已经注释掉了,因为它没有用,但在这里我可以参考:
ServiceThrottlingBehavior stb = new ServiceThrottlingBehavior
{
MaxConcurrentCalls = 400,
MaxConcurrentSessions = 400,
MaxConcurrentInstances = 400
};
host.Description.Behaviors.RemoveAll<ServiceThrottlingBehavior>();
host.Description.Behaviors.Add(stb);
有没有人有类似问题的方法正常工作但在发送给调用者时仍然超时?
答案 0 :(得分:1)
这是一个难题,从我能说的一切来看,这是WCF的复杂性。它无法处理在循环中非常快速地重用的一个连接。
它似乎锁定了套接字连接,尽管试图添加GC.Collect()
并没有释放它所竞争的任何资源。
最后,我发现工作的唯一方法是为每个并发请求创建到同一端点的另一个连接,并在不同的线程上执行它们。可能不是最干净的方式,但这一切都有效。
可能派上用场的东西是我使用svc跟踪查看器监视WCF调用以尝试跟踪问题,我在本文中找到了如何使用它:http://www.codeproject.com/Articles/17258/Debugging-WCF-Apps