c# - WCF 的 ClientBase<TChannel> 在 Disposed 时如何处理 TCP 连接?

标签 c# .net wcf sockets tcp

前一段时间我看到一篇有趣的文章,解释了将 HttpClient在 using block 中将在代码执行但不关闭 TCP 套接字时处理该对象,并且 TCP 状态最终将进入 TIME_WAIT 并在该状态列表中停留 4 分钟以进行进一步的事件(默认).

所以基本上多次使用它:

using(var client = new HttpClient())
{
    //do something with http client
}

导致许多打开的 TCP 连接处于TIME_WAIT

你可以在这里阅读整篇文章:

You're using HttpClient wrong and it is destabilizing your software

所以我想知道如果我对 ClientBase<TChannel> 做同样的事情会发生什么当您右键单击项目并选择添加 添加服务引用时,由 Visual Studio 创建的派生服务类。 . 并实现了这个:

    //SomeServiceOutThere inherits from ClientBase
    using (var service = new SomeServiceOutThere()) 
    {
       var serviceRequestParameter = txtInputBox.Text;
       var result = service.BaddaBingMethod(serviceRequestParameter);
       //do some magic (see Fred Brooks quote)
    }

但是,我无法重新创建完全相同的行为,我想知道为什么。

  1. 我创建了一个小型桌面应用程序并添加了对 IIS 托管的 WCF 服务的引用。
  2. 接下来,我添加了一个按钮,基本上通过上面显示的 using 代码块调用代码。
  3. 第一次访问该服务后,我为 IP 运行 netsat,结果如下:

enter image description here

  1. 到目前为止一切顺利。我再次点击按钮,果然,新的连接建立了,而第一个连接进入了TIME_WAIT状态:

enter image description here

  1. 但是,在此之后,每次我访问该服务时,它都会使用ESTABLISHED 连接,并且不再像HttpClient 中那样打开。演示(即使将不同的参数传递给服务,但保持应用程序运行)。

似乎 WCF 足够聪明,可以意识到已经建立了与服务器的连接,并使用它。

有趣的是,当我重复上述过程,但在每次调用服务之间停止并重新启动应用程序时,我确实得到了与 HttpClient 相同的行为。 :

enter image description here

ClientBase 还有一些其他潜在问题(例如 see here ),我知道如果服务流量相对较低或服务器设置为大量最大连接,临时打开套接字可能根本不是问题,但我仍然希望能够可靠地测试这是否会成为问题,以及在什么条件下(例如,正在运行的 Windows 服务与 WCF 服务相比较桌面应用程序)。

有什么想法吗?

最佳答案

WCF 内部不使用 HttpClient。 WCF 可能使用 HttpWebRequest,因为该 API 当时可用,而且它可能会快一点,因为 HttpClient 是它的包装器。

WCF 适用于高性能用例,因此他们确保重用 HTTP 连接。在我看来,默认情况下不重用连接是 Not Acceptable 。这是 HttpClient 的错误或设计问题。

4.6.2 Desktop .NET Framework 在 HttpClienthandler.Dispose 中包含这一行:

ServicePointManager.CloseConnectionGroups(this.connectionGroupName);

由于此代码不在 CoreClr 中,因此没有相关文档。我不知道为什么要添加这个。它甚至有一个错误,因为 this.connectionGroupName = RuntimeHelpers.GetHashCode(this).ToString(NumberFormatInfo.InvariantInfo); 在 ctor 中。两个 connectionGroupName 可能会发生冲突。这是获取本应唯一的随机数的糟糕方法。

如果重新启动进程,则无法重用现有连接。这就是您看到旧连接处于 TIME_WAIT 状态的原因。这两个过程是无关的。因为它们(和操作系统)中的代码知道它们没有以任何方式合作。跨进程重启也很难保存 TCP 连接(但有可能)。据我所知,没有任何应用可以做到这一点。

您是否经常启动流程,以至于这可能会成为一个问题?不太可能,但如果是,您可以应用一种通用解决方法,例如减少 TIME_WAIT 持续时间。

复制这个很容易:只需在一个循环中启动 100k 个测试过程。

关于c# - WCF 的 ClientBase<TChannel> 在 Disposed 时如何处理 TCP 连接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40058217/

相关文章:

c# - 提供了 XmlNamespaceManager,但仍然得到 "Namespace Manager or XsltContext needed"

c# - 具有派生类型的泛型类型推断

c# - 在外部命名空间中引用方法/变量是否比完全包含它更节省内存?

.net - 禁用菜单项的下划线解释

.net - 我应该如何保证 "message"被发送并存储一次且仅一次?

c# - 将 Linq 表达式转换为 URI : The method 'Select' is not supported 时出错

.net - http.sys 和响应时间记录

c# - 是否有任何理由锁定 new object() 以外的东西?

wcf - 通过互联网访问 WCF 服务?

vb.net - 通过 HTTPS 的 wsHTTPBinding 导致错误 400 'Bad Request'