【问题标题】:How long is a WCF connection held open?WCF 连接保持打开多长时间?
【发布时间】:2016-03-08 19:36:52
【问题描述】:

我正在运行一个小型 WCF 客户端应用程序,它每隔几分钟就连接到 IIS 服务器以下载数据。大约有 500 个这样的客户端用于 2 或 3 个服务器,我的基本代码是这样的:

Client connection = null;

try
{
    connection = new Client();
    List<TPointer> objects = connection.GetList();

    // Some work on List<T>

    foreach (TPointer pointer in objects)
    {
        T data = GetDataFromStream(pointer, connection);

        // Some additional processing on T
    }

    connection.SendMoreData();    

    // More work
}
catch (...)
{
    // Exception handling for various exceptions
}
finally
{
    // Handle Close() or Abort()
    if (connection != null)
        connection.Close();
}

当我为大量 TPointer 模拟一次运行所有客户端时,我开始遇到以下错误:

System.TimeoutException:请求通道在 00:01:00 后等待回复时超时。

这似乎是可能由于多种原因而发生的错误之一。据我所知,服务器可能只是被淹没了,或者我可能请求了太大/太多的对象,并且下载时间太长(不过一分钟?)。增加超时是一种选择,但我想了解实际问题而不是修复症状。

鉴于我无法控制服务器,我该如何简化我的客户端?

  1. 我实际上并不确定超时中提到的“请求通道”指的是什么。超时是否从我创建 new Client() 到我调用 Client.Close() 开始计时?或者我发送到服务器的每个特定请求(例如GetListGetData)是否需要一分钟?在每次调用服务器之间关闭Client() 值得我花时间吗? (我希望不会……那会很丑)

  2. 对我接收的数据量进行分块会有帮助吗? GetList() 调用可能非常大(达到数千个)。我可以尝试一次获取几个对象并完成后期处理以供以后使用...

编辑:

由于少数人提到了流媒体:

Client 绑定使用TransferMode.StreamedResponseGetDataFromStream() 使用从 TPointer 派生的 Stream,SendMoreData() 的有效负载大小或多或少可以忽略不计。

只有GetList()实际上返回一个非流对象,但我不清楚这是否会影响传输方法。

【问题讨论】:

    标签: c# .net wcf iis


    【解决方案1】:

    或者我发送到服务器的每个特定请求(例如 GetList 或 GetData)是否会再等待一分钟?

    超时属性适用于您正在执行的每个操作。它被重置了。如果您的超时是一分钟,那么它会从您调用该方法的那一刻开始。

    我要做的是实施重试策略并使用客户端方法的async 版本,并在花费太长时间时在客户端上使用CancellationToken 或调用Abort()。或者,您可以在操作超时的InnerChannel 上增加或设置超时。

    client.InnerChannel.OperationTimeout = TimeSpan.FromMinutes(10);
    

    您可以在操作期间和重试策略中使用它,您可以在重试失败或成功后完全中止并重置超时。

    或者,您可以尝试流式传输您的结果,看看您是否可以单独对它们进行操作,但我不知道保持该连接打开是否会导致超时。在您拥有一切之前,您将不得不推迟对您的收藏进行操作。

    另外,在绑定中设置TransferMode = TransferMode.StreamedResponse

    【讨论】:

    • 我实际上已经在使用 StreamedResponse,尽管我没有在帖子中说清楚。添加了更多信息。但是,使用 StreamedResponse 会影响 List 的传输方式吗?
    【解决方案2】:

    我相信您所达到的超时时间是第一次响应的时间。在您的场景中,第一个响应是整个响应,因为您要返回列表,更多数据更多时间。您可能需要考虑流式传输数据而不是返回完整列表。

    【讨论】:

    • 我正在使用 TransferMode.StreamedResponse;不过,不确定返回列表而不是 Stream 对象是否意味着我实际上是在流式传输该列表。
    【解决方案3】:

    我建议修改您的 web.config 文件(wcf 端)和 app.config(客户端),添加这样的绑定部分(即超时 25 分钟而不是默认值 1 分钟):

    <bindings>
      <wsHttpBinding>
        <binding name="WSHttpBinding_IYourService"
                 openTimeout="00:25:00" 
                 closeTimeout="00:25:00" 
                 sendTimeout="00:25:00" 
                 receiveTimeout="00:25:00">
        </binding>
      </wsHttpBinding>
    </bindings>
    

    【讨论】:

      【解决方案4】:

      鉴于我无法控制服务器,如何简化我的客户端?

      基本上,当您只能控制客户端时,您无法执行此操作。操作似乎没有返回 Stream(除非指针是派生自 Stream 的类型)。

      如果您想了解更多关于一般如何实现流式传输的信息,请阅读this MSDN article

      您可以在客户端上做的所有事情都只是触及问题的表面。就像@The Anathema 在他的回答中提出的那样,您可以创建重试逻辑和/或将超时设置为更高的值。但是要根除问题的根源,您需要调查服务本身的来源,以便它可以处理更多的请求。或者让服务实例在多个服务器上运行,前面有一个负载平衡器。

      【讨论】:

        【解决方案5】:

        我最终在这里结合了答案,所以我将发布一个答案。我将GetList() 分块到一定的大小,以避免长时间保持连接打开(它通常对代码也有积极影响,因为我暂时保留较少的内存。)我已经制定了重试策略,但是正如 The Anathema 和其他几个人所建议的那样,还将计划搞砸超时。

        【讨论】:

          猜你喜欢
          • 2018-01-23
          • 2012-12-21
          • 2021-05-11
          • 2015-08-09
          • 1970-01-01
          • 2015-01-19
          • 2023-03-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多