我很难过.也许有人可以对我观察到的WCF客户端行为有所了解.
使用WCF示例,我开始使用不同的WCF客户端/服务器通信方法.在并行执行1M测试请求时,我使用SysInternals TcpView来监视开放端口.现在,至少有4种不同的方式来调用客户端:
现在,据我所知,只有选项2-4,显式调用client.Close().在执行期间,我看到许多端口处于TIME_WAIT状态.由于依赖GC,我期望选项1成为最糟糕的情况.然而,令我惊讶的是,它似乎是最干净的,这意味着,它不会留下任何挥之不去的端口.
我错过了什么?
更新:源代码
private static void RunClientWorse(ConcurrentBag<double> cb)
{
var client = new CalculatorClient();
client.Endpoint.Address = new EndpointAddress("net.tcp://localhost:8000/ServiceModelSamples/service");
RunClientCommon(cb, client);
}
private static void RunClientBetter(ConcurrentBag<double> cb)
{
using (var client = new CalculatorClient())
{
client.Endpoint.Address = new EndpointAddress("net.tcp://localhost:8000/ServiceModelSamples/service");
RunClientCommon(cb, client);
}
}
private static void RunClientBest(ConcurrentBag<double> cb)
{
const string Uri = "net.tcp://localhost:8000/ServiceModelSamples/service";
var address = new EndpointAddress(Uri);
//var binding = new NetTcpBinding("netTcpBinding_ICalculator");
using (var factory = new ChannelFactory<ICalculator>("netTcpBinding_ICalculator",address))
{
ICalculator client = factory.CreateChannel();
((IContextChannel)client).OperationTimeout = TimeSpan.FromSeconds(60);
RunClientCommon(cb, client);
}
}
private static void RunClientBestExt(ConcurrentBag<double> cb)
{
const string Uri = "net.tcp://localhost:8000/ServiceModelSamples/service";
var address = new EndpointAddress(Uri);
//var binding = new NetTcpBinding("netTcpBinding_ICalculator");
new ChannelFactory<ICalculator>("netTcpBinding_ICalculator", address).Using(
factory =>
{
ICalculator client = factory.CreateChannel();
((IContextChannel)client).OperationTimeout = TimeSpan.FromSeconds(60);
RunClientCommon(cb, client);
});
}
Run Code Online (Sandbox Code Playgroud)
我想我已经弄清楚了。GC 不会调用 ClientBase 上的 Dispose。这就是连接不会处于 TIME_WAIT 状态的原因。所以我决定遵循相同的模式并创建一个新的 WCF 扩展:
public static void UsingAbort<T>(this T client, Action<T> work)
where T : ICommunicationObject
{
try
{
work(client);
client.Abort();
}
catch (CommunicationException e)
{
Logger.Warn(e);
client.Abort();
}
catch (TimeoutException e)
{
Logger.Warn(e);
client.Abort();
}
catch (Exception e)
{
Logger.Warn(e);
client.Abort();
throw;
}
}
}
Run Code Online (Sandbox Code Playgroud)
这样,在请求结束时,它将简单地中止连接而不是关闭它。