2

我正在使用 WCF 流将文件从 WCF 客户端传输到使用netTcpBinding.

一旦客户端使用 Stream 实例调用服务,服务将开始通过套接字连接 ( StreamConnection) 从 Stream 实例读取。但是,如果服务端读取流的过程中发生异常,客户端不能立即得到异常。

sendTimeout我发现了与绑定有关的延迟期。如果我设置sendTimeout=20 seconds了,客户端会在 20 秒延迟后得到异常;如果sendTimeout = 1 second,客户端立即获得异常。

我做了一些研究。我的理解是,即使在服务上抛出异常,它也不会抛出给客户端,直到StreamConnection.Read()/StreamConnection.Write(). 这个超时时间看起来与绑定 sendTimeout 同步。

是否可以保留sendTimeout并让客户立即获得异常?

这是服务绑定,(为了传输大文件,我更改了maxReceivedMessageSize、sendTimeout和receiveTimeout等的值)

  <netTcpBinding>
    <binding  name="StreamingNetTCPBinding" transferMode="Streamed" maxConnections="500" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" sendTimeout="00:45:00" receiveTimeout="23:00:00" listenBacklog="20">
      <readerQuotas maxArrayLength="2147483647" maxDepth="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" maxStringContentLength="2147483647" />
    </binding>
  </netTcpBinding>
4

1 回答 1

0

您看到的行为是由于流模式与缓冲模式相比的语义。当使用缓冲连接时,它实际上是一个双工连接,即使在使用请求/回复时也是如此。挂起的接收总是被发布以接受传入的请求或对任何未完成的请求的回复。这就是为什么您可以在单个 NetTcp 连接上从具有单个通道的多个线程发送多个未完成的请求。在流模式下,当发出请求时,调用实例拥有通道,直到调用完成。请求流被发送,只有在它被发送之后,我们才会在连接上发出接收/读取。这是因为如果请求消息实际上尚未完全发送,即使响应消息是故障消息,您也无法获得对请求消息的回复。

根据您的要求,您有几个处理此问题的选项,其中大部分只需要更改您的服务代码。在服务端,如果你有抛出异常,你需要捕获异常,排空传入的流,然后重新抛出异常,这将导致返回错误消息。当响应流被完全读取时,客户端已经完成了所有的发送,现在正在等待响应。这确实需要发送整个请求流,并且在大型请求早期失败的情况下,这可能是不可取的。如果不希望花费时间/带宽来接收消息的其余部分,那么您可以在服务端对通道进行故障处理(使用 Abort())。这将导致套接字断开连接,您将在客户端收到 CommunicationException。这样做的缺点是没有收到有关问题所在的信息,但会非常直接。

需要在客户端和服务器端进行更改的另一个选项是使用两个通道并使用第二个通道接收有关第一个通道上请求状态的 OOB 信息。

于 2016-04-13T18:49:09.877 回答