【问题标题】:WCF using, closing and extensionsWCF 使用、关闭和扩展
【发布时间】:2013-05-08 14:09:02
【问题描述】:

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

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

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

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

【问题讨论】:

  • 您缺少一些源代码...我们可以看看您的单元测试吗?
  • 参见stackoverflow.com/questions/573872/… - using 块可能会导致 WCF 出现问题。
  • 感谢链接,读起来很有趣,但它仍然不能解释为什么 GC 没有留下 TIME_WAIT,但 client.Close() 会。

标签: c# wcf


【解决方案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;
        }
    }
}

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

【讨论】:

  • 您的新模式的问题是 Abort() 没有通知服务客户端关闭。通过不在 try 块中的打开连接上调用 Close(),您将在服务器上保持连接打开,直到它们超时。推荐阅读:stackoverflow.com/questions/573872/…
  • 我不相信@ErnieL 的情况。根据 Microsoft 文档,Abort() 导致 ClientBase 对象立即从其当前状态转换为关闭状态。端口关闭服务器端似乎证实了这一点。我错过了什么吗?
  • 文档喜欢说 Abort() 是“立即的”,而 Close() 是“优雅的”。例如:msdn.microsoft.com/en-us/library/ms195520.aspx。这么说吧:您的模式 从不 调用 Close() 并且有据可查的是 Dispose() 调用 Close() 而不是 Abort()。那么,如果你的模式是正确的,那么为什么 Close() 会出现在界面中呢?
  • 如果端口,在服务器端的 TcpView 中,将状态从 ESTABLISHED 更改为“gone”,是否确认连接已关闭?如果我调用 Close() 或 Dispose(),它会更改为 TIME_WAIT,持续 30 秒(如果使用默认注册表设置,则为 4 分钟)。我的模式不需要多调用处理,所以从这个角度来看,如果 Abort 实际上关闭了连接,Abort 与 Close 一样好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-02
  • 2011-06-25
  • 2018-09-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多