HTTP.SYS trennt HTTP-Bindungen für selbst gehostete WCF-Dienste.
Dieser Artikel hilft Ihnen bei der Behebung des Problems, das bewirkt, dass ein Windows Server 2012 R2-basierten Server eine zugrunde liegende TCP-Verbindung abgibt.
Ursprüngliche Produktversion: Windows Communication Foundation
Ursprüngliche KB-Nummer: 3137046
Problembeschreibung
Bei einem selbst gehosteten Windows Communication Foundation (WCF)-Dienst auf einem Server, der Windows Server 2012 R2 ausführt und HTTP-basierte Bindungen verwendet (z. basicHttpBinding B.), legt der Server die zugrunde liegende TCP-Verbindung zeitweise ab. Wenn dieses Problem auftritt, können Sie es in den HTTP.SYS Protokollen sehen, die sich in der Regel im C:\WINDOWS\System32\LogFiles\HTTPERR Ordner befinden. Die Protokolldateien sollten über einen Eintrag verfügen, der als Grund angegeben Timer_MinBytesPerSecond wird. Dieses Problem tritt in Windows Server 2008 R2 nicht auf.
Der Protokolleintrag sieht wie folgt aus:
#Fields: date time c-ip c-port s-ip s-port cs-version cs-method cs-uri sc-status s-siteid s-reason s-queuename
date time 10.145.136.58 41079 10.171.70.136 8888 HTTP/1.1 POST /MySelfHostedService/TestService1 - - Timer_MinBytesPerSecond -
date time 10.145.136.58 41106 10.171.70.136 8888 HTTP/1.1 POST /MySelfHostedService/TestService1 - - Timer_MinBytesPerSecond -
date time 10.145.136.58 40995 10.171.70.136 8888 HTTP/1.1 POST /MySelfHostedService/TestService1 - - Timer_MinBytesPerSecond -
date time 10.145.136.58 41022 10.171.70.136 8888 HTTP/1.1 POST /MySelfHostedService/TestService1 - - Timer_MinBytesPerSecond -
In den WCF-Ablaufverfolgungen schlägt der Dienst während eines Empfangsbytevorgangs mit System.Net.HttpListenerException fehl, wie im folgenden Beispiel gezeigt:
<Exception>
<ExceptionType>System.ServiceModel.CommunicationException, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
<Message>The I/O operation has been aborted because of either a thread exit or an application request</Message>
<StackTrace>
at System.ServiceModel.Channels.HttpRequestContext.ListenerHttpContext.ListenerContextHttpInput.ListenerContextInputStream.EndRead(IAsyncResult result)
at System.ServiceModel.Channels.HttpInput.ParseMessageAsyncResult.OnRead(IAsyncResult result)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.HttpRequestStream.HttpRequestStreamAsyncResult.IOCompleted(HttpRequestStreamAsyncResult asyncResult, UInt32 errorCode, UInt32 numBytes)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
</StackTrace>
<ExceptionString>System.ServiceModel.CommunicationException: The I/O operation has been aborted because of either a thread exit or an application request ---> System.Net.HttpListenerException: The I/O operation has been aborted because of either a thread exit or an application request
at System.Net.HttpRequestStream.EndRead(IAsyncResult asyncResult)
at System.ServiceModel.Channels.DetectEofStream.EndRead(IAsyncResult result)
at System.ServiceModel.Channels.HttpRequestContext.ListenerHttpContext.ListenerContextHttpInput.ListenerContextInputStream.EndRead(IAsyncResult result)
--- End of inner exception stack trace ---
</ExceptionString>
<InnerException>
<ExceptionType>System.Net.HttpListenerException, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
<Message>The I/O operation has been aborted because of either a thread exit or an application request</Message>
<StackTrace>
at System.Net.HttpRequestStream.EndRead(IAsyncResult asyncResult)
at System.ServiceModel.Channels.DetectEofStream.EndRead(IAsyncResult result)
at System.ServiceModel.Channels.HttpRequestContext.ListenerHttpContext.ListenerContextHttpInput.ListenerContextInputStream.EndRead(IAsyncResult result)
</StackTrace>
<ExceptionString>System.Net.HttpListenerException (0x80004005): The I/O operation has been aborted because of either a thread exit or an application request
at System.Net.HttpRequestStream.EndRead(IAsyncResult asyncResult)
at System.ServiceModel.Channels.DetectEofStream.EndRead(IAsyncResult result)
at System.ServiceModel.Channels.HttpRequestContext.ListenerHttpContext.ListenerContextHttpInput.ListenerContextInputStream.EndRead(IAsyncResult result)
</ExceptionString>
<NativeErrorCode>3E3</NativeErrorCode>
</InnerException>
</Exception>
Ursache
Ab Windows Server 2012 R2 wurde der Kerneltreiber, der HTTP-Anforderungen (http.sys) verarbeitet, hinsichtlich der Verarbeitung der Timer_MinBytesPerSecond Eigenschaft geändert. Standardmäßig betrachtet Http.sys jede Geschwindigkeitsrate von weniger als 150 Byte pro Sekunde als potenziellen Verbindungsangriff mit niedriger Geschwindigkeit und legt die TCP-Verbindung ab, um die Ressource freizugeben. Dieses Problem tritt in Windows Server 2008 R2 nicht auf, da der Schwellenwert für eine langsame Verbindung in Windows Server 2012 R2 viel restriktiver ist.
Problemumgehung
Um dieses Feature zu umgehen, legen Sie den minSendBytesPerSecond Wert auf 0xFFFFFFFF fest (maximal 32-Bit-Ganzzahlwert ohne Vorzeichen), der 4.294.967.295 im Dezimaltrennzeichen ist. Dieser spezifische Wert deaktiviert das Verbindungsfeature mit niedriger Geschwindigkeitsrate.
Verwenden Sie eine der folgenden Methoden, um den minSendBytesPerSecond Wert 0xFFFFFFFF festzulegen.
Methode 1: Verwenden einer Konfigurationsdatei
<system.net> <settings> <httpListener> <timeouts minSendBytesPerSecond="4294967295" /> </httpListener> </settings> </system.net>Methode 2: Programmgesteuertes Festlegen
Ändern Sie die Eigenschaft explizit im Code, wie im folgenden Beispiel gezeigt:
System.Net.HttpListenerTimeoutManager.MinSendBytesPerSecond = 4294967295
Die Programmieroption kann zu einer benutzerdefinierten Option gemacht serviceBehavior werden, wenn eine Codeänderung im Dienst keine Option ist. Das heißt, ein Verhalten kann in einen vorhandenen Dienst integriert werden, indem eine DLL abgelegt und die Konfiguration geändert wird, wie im folgenden Beispiel gezeigt:
Öffnen Sie Ihre Lösung in Visual Studio, und fügen Sie ein neues Klassenbibliotheksprojekt hinzu. Nennen Sie es
BehaviorProject.Erstellen Sie eine Klasse mit dem Namen
HttpListenerBehavior.Aktualisieren Sie es mit dem folgenden Quellcode:
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(); } } }Erstellen Sie die Bibliotheksanwendung.
Kopieren Sie die generierte DLL in Ihren Anwendungsordner.
Öffnen Sie die Anwendungskonfigurationsdatei, suchen Sie das
<system.serviceModel>Tag, und fügen Sie das folgende benutzerdefinierte Verhalten hinzu:<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>
Weitere Informationen
Verwenden Sie eine der folgenden Methoden, um zu bestimmen, ob die Änderungen wirksam waren.
Methode 1
Erfassen Sie eine Speicherabbilddatei, nachdem serviceHost geöffnet wurde.
Sichern Sie das Objekt vom
System.Net.HttpListenerTimeoutManagerTyp, und lesen Sie dieminSendBytesPerSecondEigenschaft.0:000> !DumpObj /d 02694a64 Name: System.Net.HttpListenerTimeoutManager MethodTable: 7308b070 EEClass: 72ec5238 Size: 20(0x14) bytes File: C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll Fields: MT Field Offset Type VT Attr Value Name 73092254 4001605 4 ....Net.HttpListener 0 instance 026932f0 listener 73c755d4 4001606 8 System.Int32[] 0 instance 02694a78 timeouts 73c7ef20 4001607 c System.UInt32 1 instance 4294967295 minSendBytesPerSecond <-----------------Hinweis
Der Wert für
minSendBytesPerSecondist 4294967295.
Methode 2
Öffnen Sie im Administratormodus cmd.exe, und führen Sie den folgenden Befehl an einer Eingabeaufforderung aus (nachdem serviceHost geöffnet wurde):
netsh http show servicestate view="session" >%temp%\netshOutput.txtFühren Sie den folgenden Befehl aus, um die netshOutput.txt Datei zu öffnen. Er wird in Editor geöffnet.
start %temp%\netshOutput.txtSuchen Sie nach der Portnummer der Dienstanwendung (z. B. 8888), und zeigen Sie dann Ihre Sitzung an. Dies ist der Schritt, um zu überprüfen, ob die minimale Senderate (Bytes/s) mit dem 4294967295 Wert überschrieben wird.
Es sollte ein Eintrag angezeigt werden, der folgendermaßen aussieht:
Server session ID: FE00000320000021 Version: 2.0 State: Active Properties: Max bandwidth: 4294967295 Timeouts: Entity body timeout (secs): 120 Drain entity body timeout (secs): 120 Request queue timeout (secs): 120 Idle connection timeout (secs): 120 Header wait timeout (secs): 120 Minimum send rate (bytes/sec): 150 URL groups: URL group ID: FD00000340000001 State: Active Request queue name: Request queue is unnamed. Properties: Max bandwidth: inherited Max connections: inherited Timeouts: Entity body timeout (secs): 0 Drain entity body timeout (secs): 0 Request queue timeout (secs): 0 Idle connection timeout (secs): 0 Header wait timeout (secs): 0 Minimum send rate (bytes/sec): 4294967295 <------------------- Number of registered URLs: 1 Registered URLs: HTTP://+:8888/TESTSERVICE1/
Weitere Informationen finden Sie unter "HttpListenerTimeoutManager.MinSendBytesPerSecond"-Eigenschaft.