什么130秒超时正在杀死我的WCF流媒体服务电话?

jpi*_*son 15 streaming wcf iis-7 .net-4.0 basichttpbinding

就在最近,我开始研究WCF流的棘手问题,如果客户端在发送到服务器之间等待的时间超过130秒,则会产生CommunicationException.

以下是完整的例外情况:

System.ServiceModel.CommunicationException was unhandled by user code
  HResult=-2146233087
  Message=The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '23:59:59.9110000'.
  Source=mscorlib
  StackTrace:
    Server stack trace: 
       at System.ServiceModel.Channels.HttpOutput.WebRequestHttpOutput.WebRequestOutputStream.Write(Byte[] buffer, Int32 offset, Int32 count)
       at System.IO.BufferedStream.Write(Byte[] array, Int32 offset, Int32 count)
       at System.Xml.XmlStreamNodeWriter.FlushBuffer()
       at System.Xml.XmlStreamNodeWriter.GetBuffer(Int32 count, Int32& offset)
       at System.Xml.XmlUTF8NodeWriter.InternalWriteBase64Text(Byte[] buffer, Int32 offset, Int32 count)
       at System.Xml.XmlBaseWriter.WriteBase64(Byte[] buffer, Int32 offset, Int32 count)
       at System.Xml.XmlDictionaryWriter.WriteValue(IStreamProvider value)
       at System.ServiceModel.Dispatcher.StreamFormatter.Serialize(XmlDictionaryWriter writer, Object[] parameters, Object returnValue)
       at System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage.OperationFormatterBodyWriter.OnWriteBodyContents(XmlDictionaryWriter writer)
       at System.ServiceModel.Channels.Message.OnWriteMessage(XmlDictionaryWriter writer)
       at System.ServiceModel.Channels.TextMessageEncoderFactory.TextMessageEncoder.WriteMessage(Message message, Stream stream)
       at System.ServiceModel.Channels.HttpOutput.WriteStreamedMessage(TimeSpan timeout)
       at System.ServiceModel.Channels.HttpOutput.Send(TimeSpan timeout)
       at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.SendRequest(Message message, TimeSpan timeout)
       at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
       at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
       at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
       at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
    Exception rethrown at [0]: 
       at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
       at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
       at WcfService.IStreamingService.SendStream(MyStreamUpRequest request)
       at Client.Program.<Main>b__0() in c:\Users\jpierson\Documents\Visual Studio 2012\Projects\WcfStreamingTest\Client\Program.cs:line 44
       at System.Threading.Tasks.Task.Execute()
  InnerException: System.IO.IOException
       HResult=-2146232800
       Message=Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host.
       Source=System
       StackTrace:
            at System.Net.Sockets.NetworkStream.MultipleWrite(BufferOffsetSize[] buffers)
            at System.Net.ConnectStream.InternalWrite(Boolean async, Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
            at System.Net.ConnectStream.Write(Byte[] buffer, Int32 offset, Int32 size)
            at System.ServiceModel.Channels.BytesReadPositionStream.Write(Byte[] buffer, Int32 offset, Int32 count)
            at System.ServiceModel.Channels.HttpOutput.WebRequestHttpOutput.WebRequestOutputStream.Write(Byte[] buffer, Int32 offset, Int32 count)
       InnerException: System.Net.Sockets.SocketException
            HResult=-2147467259
            Message=An existing connection was forcibly closed by the remote host
            Source=System
            ErrorCode=10054
            NativeErrorCode=10054
            StackTrace:
                 at System.Net.Sockets.Socket.MultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags)
                 at System.Net.Sockets.NetworkStream.MultipleWrite(BufferOffsetSize[] buffers)
            InnerException: 
Run Code Online (Sandbox Code Playgroud)

由于连接不活动,服务器似乎已过早关闭连接.如果我给服务器一个脉冲,甚至一次一个字节,那么我永远不会得到这个异常,我可以继续无限期地传输数据.我构建了一个非常简单的示例应用程序来演示这个使用basicHttpBinding和Streamed transferMode,我在客户端的自定义流实现中插入一个延迟130秒的人工延迟.这模拟类似于缓冲区欠载条件的情况,其中来自客户端的服务调用中提供的流不会足够快地将数据提供给WCF基础结构,以满足某种似乎在130秒左右的无法识别的超时值.标记.

使用WCF服务跟踪工具,我能够找到与读取信息的HttpException"因为底层的请求已完成客户端断开.不再有可用的HttpContext的."

从IIS Express跟踪日志文件中,我看到一条条目:"由于线程退出或应用程序请求,I/O操作已中止.(0x800703e3)"

我已经将服务器和客户端超时配置为使用超过130秒标记的值来排除它们.我已经在IIS Express中尝试了idleTimeout以及一系列与ASP.NET相关的超时值,以便发现这个问题的来源,但到目前为止还没有运气.到目前为止,我能找到的最好的信息是开发人员对FireFox问题跟踪器评论,该开发人员描述了在WCF架构之外工作的类似问题.出于这个原因,我猜这个问题可能与IIS7或Windows Server有关.

服务器Web.config上的自定义绑定

<binding name="myHttpBindingConfiguration"
         closeTimeout="02:00:00"
         openTimeout="02:00:00"
         receiveTimeout="02:00:00"
         sendTimeout="02:00:00">
  <textMessageEncoding messageVersion="Soap11" />
  <httpTransport maxBufferSize="65536"                        
                 maxReceivedMessageSize="2147483647"
                 maxBufferPoolSize="2147483647"
                 transferMode="Streamed" />
</binding>
Run Code Online (Sandbox Code Playgroud)

代码中的客户端配置:

    var binding = new BasicHttpBinding();
    binding.MaxReceivedMessageSize = _maxReceivedMessageSize;
    binding.MaxBufferSize = 65536;
    binding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
    binding.ReaderQuotas.MaxArrayLength = int.MaxValue;
    binding.TransferMode = TransferMode.Streamed;
    binding.ReceiveTimeout = TimeSpan.FromDays(1);
    binding.OpenTimeout = TimeSpan.FromDays(1);
    binding.SendTimeout = TimeSpan.FromDays(1);
    binding.CloseTimeout = TimeSpan.FromDays(1);
Run Code Online (Sandbox Code Playgroud)

为了回应wals的想法,试图看看我是否通过自我托管我的服务得到任何不同的结果我想添加我这样做,并发现我得到与在IIS中托管时相同的结果.这是什么意思?我的猜测是,这意味着问题出在WCF或Windows中的底层网络基础设施中.我正在使用Windows 7 64位,我们通过运行各种客户端并在Windows 2008 Server上运行服务部分来发现此问题.

更新2013-01-15

一旦我意识到WCF在Windows 7上的自托管方案中使用了HTTP.sys,我发现了一些新的线索感谢DarkWanderer.这让我看到了我可以为HTTP.sys配置的内容以及人们报告的问题类型对于听起来与我正在经历的类似的HTTP.sys.这导致我找到位于C:\ Windows\System32\LogFiles\HTTPERR\httperr1.log的日志文件,该文件似乎记录了HTTP.sys方面的特定类型的HTTP问题.在这个日志中,每次运行测试时都会看到以下类型的日志条目.

2013-01-15 17:17:12 127.0.0.1 59111 127.0.0.1 52733 HTTP/1.1 POST /StreamingService.svc - - Timer_EntityBody -

因此,要找出哪些条件可能导致Timer_EntityBody错误以及IIS7或其他地方的哪些设置可能会影响何时以及是否发生该错误.

来自IIS官方网站:

连接在请求实体主体到达之前到期.当显然请求具有实体主体时,HTTP API将打开Timer_EntityBody计时器.最初,此计时器的限制设置为connectionTimeout值.每次在此请求上收到另一个数据指示时,HTTP API将重置计时器,以便为connectionTimeout属性中指定的连接提供更多分钟.

尝试修改connectionTimeout属性作为上面的参考建议在IIS的applicationhost.config中似乎没有任何区别.也许IIS Express会忽略此配置并在内部使用硬编码值?试图对我自己的东西,我发现有添加,显示,并添加超时值,以便让我去,我想出了下面的命令可惜这样做似乎没有对这个错误有什么影响无论是新的netsh HTTP命令.

netsh http add timeout timeouttype = IdleConnectionTimeout value = 300

jpi*_*son 16

事实证明,此问题是由HTTP.sys使用的连接超时值引起的,可以通过IIS管理器通过单个站点的"高级设置"指定.默认情况下,此值配置为在120秒内未收到标题和正文时超时连接.如果接收到来自正文的数据脉冲,则服务器在超时值内重新启动计时器(Timer_EntityBody),然后重置计时器以等待其他数据.

IIS中的连接超时设置

这就像有关Timer_EntityBodyconnectionTimeout 的文档一样,但很难确定,因为看起来IIS Express忽略了applicationhost.config中的limits元素中指定的connectionTimeout值,无论文档说什么.为了确定这一点,我必须在我的开发机器上安装完整版本的IIS,并在那里托管我的网站后修改上面的设置.

由于我们在Windows 2008上的IIS下托管真实服务,上述解决方案对我有用,但问题仍然是如何在您自我托管的情况下正确修改连接超时值.