5

我难住了。也许有人可以对我观察到的 WCF 客户端行为有所了解。

使用 WCF 示例,我开始尝试不同的 WCF 客户端/服务器通信方法。在并行执行 1M 的测试请求时,我使用 SysInternals TcpView 来监控打开的端口。现在,至少有 4 种不同的方式来调用客户端:

  1. 创建客户端,做你的事,让GC收集
  2. 在 using 块中创建客户端,而不是做你的事
  3. 在 using 块中从工厂创建客户端通道,而不是做你的事情
  4. 创建客户端或通道,但使用WCF 扩展来做你的事情

现在,据我所知,只有选项 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);
                });
    }
4

1 回答 1

1

我想通了,我想。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;
        }
    }
}

这样,在请求结束时,它将简单地中止连接而不是关闭它。

于 2013-05-08T17:23:40.403 回答