简体   繁体   English

WCF:通过netTcpBinding通过TransferMode = Streamed将文件传输到服务器时,对客户端的响应延迟

[英]WCF: response to client delayed when transferring file to server with TransferMode=Streamed over netTcpBinding

I'm using WCF streamming to transfer file from WCF client to service with netTcpBinding . 我正在使用WCF流将文件从WCF客户端传输到具有netTcpBinding服务。

Once client makes a call to the service with a Stream instance, the service will start to read from the Stream instance over socket connection ( StreamConnection ). 客户端使用Stream实例调用服务后,该服务将开始通过套接字连接( StreamConnection )从Stream实例读取。 But, if exception happens in the procedure of reading from stream on the service side, the client side can't get the exception immediately. 但是,如果在服务端从流读取的过程中发生异常,则客户端将无法立即获取异常。

I found the delay period related to sendTimeout of binding. 我发现与绑定的sendTimeout有关的延迟时间。 If I set sendTimeout=20 seconds , the client gets the exception in 20 seconds delay; 如果我设置sendTimeout=20 seconds ,则客户端将在20秒的延迟内获得异常; sendTimeout=20 seconds ,客户端将获得异常。 and if sendTimeout = 1 second , the client gets exception immediately. 如果sendTimeout = 1 second ,则客户端立即获取异常。

I did some research. 我做了一些研究。 My understanding is, even when the exception is thrown on the service, it will not throw to client untill the time out of StreamConnection.Read()/StreamConnection.Write() . 我的理解是,即使在服务上引发异常时,也不会在StreamConnection.Read()/StreamConnection.Write()超时之前将异常引发给客户端。 This time out period looks synchronized with binding sendTimeout. 此超时时间看起来与绑定sendTimeout同步。

Is it possible to keep the sendTimeout and let the client get exception immediately? 是否可以保留sendTimeout并让客户端立即获取异常?

Here is the service binding, (In order to transfer file with large size, I change the value of maxReceivedMessageSize, sendTimeout and receiveTimeout etc) 这是服务绑定, (为了传输大文件,我更改了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>

The behavior you are seeing is due to the semantics of streamed mode compared with buffered. 您看到的行为是由于流模式与缓冲模式相比的语义所致。 When using a buffered connection, underneath it's actually a duplex connection, even when using request/reply. 使用缓冲连接时,即使使用请求/答复,其下方实际上也是双工连接。 A pending receive is always posted to accept incoming requests or replies to any outstanding requests. 待处理的收货总是过帐以接受传入的请求或对任何未完成的请求的答复。 This is why you can have multiple outstanding requests sent on a single NetTcp connection from multiple threads with a single channel. 这就是为什么您可以通过单个通道从多个线程在单个NetTcp连接上发送多个未完成请求的原因。 With streamed mode, when a request is being made, the instance of the call owns the channel until the call has completed. 在流模式下,发出请求时,调用实例拥有该通道,直到调用完成为止。 The request stream is sent, and only after it has been sent do we issue a receive/read on the connection. 发送请求流,并且只有在发送请求流之后,我们才会在连接上发出接收/读取操作。 This is because you can't have a reply to a request message if the request message hasn't actually been fully sent, even when the response message is a Fault message. 这是因为,即使实际上未完整发送请求消息,也无法回复请求消息。

You have a few options on how to deal with this depending on your requirements, most of which will require a change only in your service code. 您可以根据自己的需求选择几种处理方式,其中大多数只需要更改服务代码即可。 On the service side, if you have an exception thrown, you need to catch the exception, drain the incoming stream and then re-throw the exception which will cause the Fault message to be returned. 在服务端,如果引发了异常,则需要捕获该异常,排空传入的流,然后重新引发该异常,这将导致返回故障消息。 As the response stream was completely read, the client has completed all it's sending and is now waiting for the response. 完全读取响应流后,客户端已完成所有发送,现在正在等待响应。 This does require the entire request stream to be sent, and in the case of a large request failing early, this may be undesirable. 这确实需要发送整个请求流,并且在大型请求过早失败的情况下,这可能是不希望的。 If it's the case that it is undesirable to spend the time/bandwidth to receive the rest of the message, then you could fault the channel (using Abort()) on the service side. 如果不希望花费时间/带宽来接收其余消息,则可以在服务端对通道进行故障处理(使用Abort())。 This will cause the socket to be disconnected and you will get a CommunicationException on the client side. 这将导致套接字断开连接,并且您将在客户端获得CommunicationException。 This has the disadvantage of not receiving information about what went wrong, but will be pretty immediate. 这样做的缺点是无法接收到有关发生问题的信息,但会立即发生。

Another option which requires changes on the client and server side is to use two channels and use the second channel to receive OOB info about the status of the request on the first channel. 需要在客户端和服务器端进行更改的另一个选项是使用两个通道,并使用第二个通道在第一个通道上接收有关请求状态的OOB信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM