HTTP。SYS 强制断开自我承载的 WCF 服务的 HTTP 的绑定

重要说明:本文是由 Microsoft 机器翻译软件进行的翻译并可能由 Microsoft 社区通过社区翻译机构(CTF)技术进行后期编辑,或可能是由人工进行的翻译。Microsoft 同时向您提供机器翻译、人工翻译及社区后期编辑的文章,以便对我们知识库中的所有文章以多种语言提供访问。翻译的文章可能存在词汇、句法和/或语法方面的错误。Microsoft 对由于内容的误译或客户对内容的使用所导致的任何不准确、错误或损失不承担责任。

点击这里察看该文章的英文版: 3137046
症状
在自主 Windows 通讯基础 (WCF) 服务正在运行 Windows Server 2012 R2 并使用基于 HTTP 的绑定 (如basicHttpBinding) 的服务器上,服务器间歇性掉线基础的 TCP 连接。发生此问题时,您可以看到它在 HTTP。通常可以在 C:\WINDOWS\System32\LogFiles\HTTPERR 文件夹中找到的系统日志。日志文件应该指出,作为原因的Timer_MinBytesPerSecond条目。在 Windows Server 2008 R2 中不会出现此问题。

日志项如下所示 ︰
#Fields ︰ 日期时间 c ip c 端口 ip s s 端口 cs 版 cs 方法 cs uri sc 状态 s 站点 id s 原因 s-queuename
日期时间 10.145.136.58 41079 10.171.70.136 8888 HTTP/1.1 发布 /MySelfHostedService/TestService1-Timer_MinBytesPerSecond-
日期时间 10.145.136.58 41106 10.171.70.136 8888 HTTP/1.1 发布 /MySelfHostedService/TestService1-Timer_MinBytesPerSecond-
日期时间 10.145.136.58 40995 10.171.70.136 8888 HTTP/1.1 发布 /MySelfHostedService/TestService1-Timer_MinBytesPerSecond-
日期时间 10.145.136.58 41022 10.171.70.136 8888 HTTP/1.1 发布 /MySelfHostedService/TestService1-Timer_MinBytesPerSecond-
在 WCF 跟踪,服务失败期间接收的字节操作System.Net.HttpListenerException,如下面的示例所示 ︰
<Exception>
<ExceptionType>System.ServiceModel.CommunicationException,System.ServiceModel,版本 = 4.0.0.0,区域性程序 = b77a5c561934e089</ExceptionType>
<Message>试图在不存在的网络连接上进行操作</Message>
<StackTrace>
在 System.ServiceModel.Channels.HttpOutput.ListenerResponseHttpOutput.ListenerResponseOutputStream.Close()
在 System.ServiceModel.Channels.HttpOutput.Close()
在 System.ServiceModel.Channels.HttpRequestContext.OnReply (消息消息,时间跨度超时)
在 System.ServiceModel.Channels.RequestContextBase.Reply (消息消息,时间跨度超时)
在 System.ServiceModel.Channels.HttpRequestContext.SendResponseAndClose (HttpStatusCode 状态代码、 字符串 statusDescription)
在 System.ServiceModel.Channels.HttpChannelListener'1.HandleProcessInboundException (ex,HttpRequestContext 上下文的例外)
</StackTrace>
<ExceptionString>System.ServiceModel.CommunicationException ︰ 试图操作上不存在的网络连接---&gt; System.Net.HttpListenerException ︰ 试图在不存在的网络连接上进行操作
在 (布尔释放) 的 System.Net.HttpResponseStream.Dispose
在 System.IO.Stream.Close()
在 System.ServiceModel.Channels.HttpOutput.ListenerResponseHttpOutput.ListenerResponseOutputStream.Close()
---内部异常的堆栈跟踪---结束
在 System.ServiceModel.Channels.HttpOutput.ListenerResponseHttpOutput.ListenerResponseOutputStream.Close()
在 System.ServiceModel.Channels.HttpOutput.Close()
在 System.ServiceModel.Channels.HttpRequestContext.OnReply (消息消息,时间跨度超时)
在 System.ServiceModel.Channels.RequestContextBase.Reply (消息消息,时间跨度超时)
在 System.ServiceModel.Channels.HttpRequestContext.SendResponseAndClose (HttpStatusCode 状态代码、 字符串 statusDescription)
在 System.ServiceModel.Channels.HttpChannelListener'1.HandleProcessInboundException (ex,HttpRequestContext 上下文的例外)</ExceptionString>
<InnerException>
<Exception>
<ExceptionType>System.Net.HttpListenerException,系统中,版本 = 4.0.0.0,区域性程序 = b77a5c561934e089</ExceptionType>
<Message>试图在不存在的网络连接上进行操作</Message>
<StackTrace>
在 (布尔释放) 的 System.Net.HttpResponseStream.Dispose
在 System.IO.Stream.Close()
在 System.ServiceModel.Channels.HttpOutput.ListenerResponseHttpOutput.ListenerResponseOutputStream.Close()
</StackTrace>
<ExceptionString>System.Net.HttpListenerException (0x80004005): 在不存在网络连接尝试的操作
在 (布尔释放) 的 System.Net.HttpResponseStream.Dispose
在 System.IO.Stream.Close()
在 System.ServiceModel.Channels.HttpOutput.ListenerResponseHttpOutput.ListenerResponseOutputStream.Close()</ExceptionString>
<NativeErrorCode>4 CD</NativeErrorCode>
</Exception>
</InnerException>
</Exception>
原因
从 Windows Server 2012 R2 开始,内核驱动程序处理的 HTTP 请求 (http.sys) 方面它如何处理Timer_MinBytesPerSecond属性已更改。默认情况下,Http.sys 会认为任何速度率小于 150 个字节每秒为潜在的低速连接攻击的它失去了 TCP 连接以释放资源。因为 Windows Server 2012 R2 中的慢速连接的阈值是限制性更强在 Windows Server 2008 R2 中未出现此问题。
替代方法
要变通解决此功能,请将minSendBytesPerSecond设置为值0xFFFFFFFF (最大的 32 位无符号整数值),即十进制 4294967295。此特定值禁用使用较低的速度速率连接功能。

使用下列方法之一将minSendBytesPerSecond设置为0xFFFFFFFF的值。

方法 1 ︰ 使用配置文件

 <system.net>    <settings>       <httpListener>           <timeouts minSendBytesPerSecond="4294967295" />       </httpListener>    </settings> </system.net>

方法 2 ︰ 以编程方式设置

在更改属性显式代码,如下面的示例所示 ︰

System.Net.HttpListenerTimeoutManager.MinSendBytesPerSecond = 4294967295

如果在服务中的代码更改不是一个选项,编程选项可以成为自定义 serviceBehavior。即,行为可以与现有服务集成通过除去 DLL 并更改配置,如以下示例所示 ︰
  1. 在 Visual Studio 中,打开您的解决方案并添加一个新的类库项目。将它命名为"BehaviorProject"。
  2. 创建一个名为"HttpListenerBehavior"。
  3. 更新它与下面的源代码 ︰
    namespace BehaviorProject{    public class HttpListenerBehavior : BehaviorExtensionElement, IServiceBehavior    {        public override Type BehaviorType        {            get { return this.GetType(); }        }        protected override object CreateBehavior()        {            return new HttpListenerBehavior();        }        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)        {            return;        }        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)        {                        UpdateSystemNetConfiguration();        }        private void UpdateSystemNetConfiguration()        {            ConfigurationProperty minSendBytesPerSecond;            minSendBytesPerSecond = new ConfigurationProperty("minSendBytesPerSecond",                typeof(long), (long)uint.MaxValue, null, null, ConfigurationPropertyOptions.None);            ConfigurationPropertyCollection properties;            HttpListenerTimeoutsElement timeOuts = new HttpListenerTimeoutsElement();            properties = GetMember(timeOuts, "properties") as ConfigurationPropertyCollection;            if (properties != null)            {                properties.Remove("minSendBytesPerSecond");                SetMember(timeOuts, "minSendBytesPerSecond", minSendBytesPerSecond);                properties.Add(minSendBytesPerSecond);            }        }        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)        {            return;        }        public static object GetMember(object Source, string Field)        {            string[] fields = Field.Split('.');            object curr = Source;            BindingFlags bindingFlags = BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;            bool succeeded = false;            foreach (string field in fields)            {                Type t = curr.GetType();                succeeded = false;                FieldInfo fInfo = t.GetField(field, bindingFlags);                if (fInfo != null)                {                    curr = fInfo.GetValue(curr);                    succeeded = true;                    continue;                }                PropertyInfo pInfo = t.GetProperty(field, bindingFlags);                if (pInfo != null)                {                    curr = pInfo.GetValue(curr, null);                    succeeded = true;                    continue;                }                throw new System.IndexOutOfRangeException();            }            if (succeeded) return curr;            throw new System.ArgumentNullException();        }        public static void SetMember(object Source, string Field, object Value)        {            string[] fields = Field.Split('.');            object curr = Source;            BindingFlags bindingFlags = BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public;            bool succeeded = false;            int i = 0;            foreach (string field in fields)            {                i++;                Type t = curr.GetType();                succeeded = false;                FieldInfo fInfo = t.GetField(field, bindingFlags);                if (fInfo != null)                {                    if (i == fields.Length)                        fInfo.SetValue(curr, Value);                    curr = fInfo.GetValue(curr);                    succeeded = true;                    continue;                }                PropertyInfo pInfo = t.GetProperty(field, bindingFlags);                if (pInfo != null)                {                    if (i == fields.Length)                        fInfo.SetValue(curr, Value);                    curr = pInfo.GetValue(curr, null);                    succeeded = true;                    continue;                }                throw new System.IndexOutOfRangeException();            }            if (succeeded) return;            throw new System.ArgumentNullException();        }    }}

  4. 生成库应用程序。
  5. 将生成的 DLL 复制到应用程序文件夹中。
  6. 打开应用程序配置文件中,找到<system.serviceModel>标记,并添加下面的自定义行为 ︰</system.serviceModel>
    <extensions> <behaviorExtensions> <add name="httpListenerBehavior" type="BehaviorProject.HttpListenerBehavior, BehaviorProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> </behaviorExtensions></extensions><behaviors> <serviceBehaviors> <!-- if the serviceBehavior used by the service is named, add to the appropriate named behavior --> <behavior name="customBehavior"> <!-- The behavior is referenced by the following in line. Visual Studio will mark this line with a red underline because it is not in the config schema. It can be ignored. Notice that the other behaviors (like serviceMetadata) does not need to be added if they are not currently present --> <httpListenerBehavior /> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="true"/> </behavior> </serviceBehaviors></behaviors>
更多信息
要确定此更改是否有效,请使用下列方法之一。

方法 1

  1. 捕获打开 serviceHost 内存转储文件。
  2. 转储的对象类型System.Net.HttpListenerTimeoutManager,并读取minSendBytesPerSecond属性。
0:000 > !DumpObj /d 02694a64
名称 ︰ System.Net.HttpListenerTimeoutManager
MethodTable: 7308b070
EEClass: 72ec5238
大小 ︰ 20(0x14) 字节
文件 ︰ C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll
字段 ︰
MT 字段偏移量类型 VT 属性值的名称
73092254 4001605 4...Net.HttpListener 0 026932f0 侦听器实例
73c755d4 4001606 8 System.Int32 [0] 实例 02694a78 超时
73c7ef20 4001607 c System.UInt32 1 实例 4294967295 minSendBytesPerSecond<>

注意, minSendBytesPerSecond的值为 4294967295。

方法 2
  1. 在管理员模式下,打开 cmd.exe,并 (打开 serviceHost) 后,在命令提示符下运行以下命令 ︰

    netsh http 显示 servicestate 视图 ="会话"> %temp%\netshOutput.txt
  2. 运行下面的命令以打开 netshOutput.txt 文件。它将在记事本中打开。

    开始 %temp%\netshOutput.txt
  3. 搜索服务应用程序端口号 (例如 8888),并查看您的会话。这是该步骤以验证, 4294967295值将覆盖最小发送速率 (字节/秒)。
  4. 您应该看到类似于以下内容的条目 ︰

    服务器会话 ID: FE00000320000021
    版本 ︰ 2.0
    状态 ︰ 活动
    属性 ︰
    最大带宽 ︰ 4294967295
    超时 ︰
    实体正文超时 (秒) ︰ 120
    耗尽实体正文超时 (秒) ︰ 120
    请求队列超时 (秒) ︰ 120
    空闲连接超时 (秒) ︰ 120
    标头等待超时 (秒) ︰ 120
    最小发送速率 (字节/秒) ︰ 150
    URL 组 ︰
    URL 组 ID: FD00000340000001
    状态 ︰ 活动
    请求队列名称 ︰ 请求队列尚未命名。
    属性 ︰
    最大带宽 ︰ 继承
    最大连接数 ︰ 继承
    超时 ︰
    实体正文超时 (秒) ︰ 0
    耗尽实体正文超时 (秒) ︰ 0
    请求队列超时 (秒) ︰ 0
    空闲连接超时 (秒) ︰ 0
    标头等待超时 (秒) ︰ 0
    最小发送速率 (字节/秒) ︰ 4294967295<>
    已注册 Url 数目 ︰ 1
    已注册的 Url:
    HTTP://+:8888/TESTSERVICE1/
有关详细信息,请参见 HttpListenerTimeoutManager.MinSendBytesPerSecond 属性 在 Microsoft 开发人员网络网站的主题。
注意:本篇“快速发布”文章是从 Microsoft 支持组织直接创建的。 文中包含的信息按原样提供,用于响应紧急问题。 由于发布仓促,材料可能包含印刷错误,并且可能随时修订,恕不另行通知。 有关其他注意事项,请参阅使用条款

警告:本文已自动翻译

属性

文章 ID:3137046 - 上次审阅时间:03/24/2016 22:21:00 - 修订版本: 3.0

Windows Communication Foundation 4.5, Windows Communication Foundation 4

  • kbmt KB3137046 KbMtzh
反馈