Eine langsame Leistung tritt auf, wenn Sie Daten mithilfe eines Windows Sockets-API-Programms auf einen TCP-Server kopieren.

Dieser Artikel bietet Problemumgehungen für das Problem, bei dem eine langsame Leistung auftritt, wenn Sie Daten mithilfe eines Windows Sockets-API-Programms auf einen TCP-Server kopieren.

Ursprüngliche Produktversion:   Windows Server 2012 R2, Windows 10 – alle Editionen
Ursprüngliche KB-Nummer:   823764

Problembeschreibung

Wenn Sie ein Programm ausführen, das die Windows Sockets-API verwendet, kann die Leistung beim Kopieren von Daten auf einen TCP-Server langsam sein.

Wenn Sie eine Netzwerküberwachung mit einem Netzwerkniffer wie Microsoft Network Monitor erstellen, sendet der TCP-Server ein TCP-ACK-Segment an das letzte TCP-Segment in einem TCP-Datenstrom im Zeitgeber für die verzögerte Bestätigung (auch als verzögerter ACK-Timer bekannt). Für windows-Betriebssysteme ist der Wert für diesen Timer standardmäßig 200 Millisekunden (ms). Ein typischer Datenfluss zum Senden von 64 KB an Daten sieht in etwa wie folgt aus:

Client->Server 1460 Bytes
Client->Server 1460 Bytes
Server->-Client-ACK
Client->Server 1460 Bytes
Client->Server 1460 Bytes
Server->-Client-ACK
....
Client->Server 1460 Bytes
Client->Server 1460 Bytes
Server->Client ACK-PUSH
Client->Server 1296 Byte
-> ACK 200 ms verzögert

Ursache

Dieses Problem tritt aufgrund des Architekturverhaltens der Windows Sockets-API und afd.sys. Dieses Problem tritt auf, wenn alle folgenden Bedingungen erfüllt sind:

  • Das Windows Sockets-Programm verwendet nicht blockierende Sockets.

  • Ein einzelner Sendeanruf oder ein einzelner WSASend-Aufruf füllt den gesamten zugrunde liegenden Sockets-Sendepuffer.

    Das Programm verwendet beispielsweise die Windows Sockets-Funktion, um während der Socket initialisierungsroutinen den Standard-Socket-Sendepuffer in setsockopt 32 KB zu ändern:

    setsockopt( sock, SOL_SOCKET, 32768, (char *) &val, sizeof( int ));
    

    Wenn das Programm später Daten sendet, gibt es einen Sendeanruf oder einen WSASend-Anruf aus und sendet bei jedem Senden 64 KB Daten:

    send(socket, pWrBuffer, 65536, 0);
    

    In diesem Szenario gibt das Programm jedes Mal, wenn das Programm einen Sendeaufruf mit 64 KB Daten ausgibt, einen SOCKET_ERROR-Fehlercode zurück, wenn der zugrunde liegende 32-KB-Socketpuffer gefüllt ist. Nach dem Aufrufen der WSAGetLastError-Funktion empfängt das Programm den WSAEWOULDBLOCK-Fehlercode. Die meisten Programme verwenden die Windows Sockets-Auswahlfunktion, um den Status des Sockets zu überprüfen. In diesem Szenario gibt die Select-Funktion den Socket erst als schreibbar an, wenn der Client das ausstehende TCP-ACK-Segment empfängt. In einer Windows-Umgebung kann dies aufgrund des Algorithmus für verzögerte Bestätigungen standardmäßig bis zu 200 ms dauern.

  • Der Remote-TCP-Server bestätigt alle TCP-Segmente, bevor der Client das letzte TCP-Segment mit dem festgelegten Pushbit sendet.

Problemumgehung

Verwenden Sie eine der folgenden Methoden, um dieses Problem zu beheben.

Methode 1: Verwenden von Blockieren von Sockets

Dieses Problem tritt nur bei nicht blockierenden Sockets auf. Wenn Sie einen blockierenden Socket verwenden, tritt dieses Problem nicht auf, da afd.sys den Socketpuffer unterschiedlich behandelt. Weitere Informationen zur Blockierung und nicht blockierenden Socketprogrammierung finden Sie in der Microsoft Platform SDK-Dokumentation.

Methode 2: Größe des Sockets zum Senden des Puffers größer als die Puffergröße für das Senden des Programms

Verwenden Sie zum Ändern des Sockets-Sendepuffers die Windows Sockets-Funktion, um die aktuelle Größe des Sendepuffers (SO_SNDBUF) des Sockets zu bestimmen, und verwenden Sie dann die Funktion, um die Größe des Sockets-Sendepuffers getsockopt setsockopt festzulegen. Wenn Sie fertig sind, SO_SNDBUF mindestens 1 Byte größer sein als die Größe des Programm-Sendepuffers.

Ändern Sie den Sendeanruf oder den WSASend-Aufruf, um eine Puffergröße anzugeben, die mindestens 1 Byte kleiner als der SO_SNDBUF ist. Im früheren Beispiel im Abschnitt "Ursache" dieses Artikels konnten Sie den setsockopt-Aufruf auf den folgenden Wert ändern:

setsockopt( sock, SOL_SOCKET, 65537, (char *) &val, sizeof( int ));

oder Sie können den Sendeanruf auf den folgenden Wert ändern:

send(socket, pWrBuffer, 32767, 0);

Sie können auch eine beliebige Kombination dieser Werte verwenden.

Methode 3: Ändern der TCP/IP-Einstellungen auf dem TCP-Server

Wichtig

Dieser Abschnitt, diese Methode bzw. diese Aufgabe enthält eine Beschreibung der Schritte zum Bearbeiten der Registrierung. Durch die falsche Bearbeitung der Registrierung können schwerwiegende Probleme verursacht werden. Daher ist es wichtig, bei der Ausführung der folgenden Schritte sorgfältig vorzugehen. Für zusätzlichen Schutz sichern Sie die Registrierung, bevor Sie sie ändern. Sie können die Registrierung wiederherstellen, wenn ein Problem auftritt. Weitere Informationen zum Sichern und Wiederherstellen der Registrierung finden Sie unter der folgenden Artikelnummer, um den Artikel in der Microsoft Knowledge Base zu sehen:
322756 Sichern und Wiederherstellen der Registrierung in Windows

Ändern Sie die TCP/IP-Einstellungen auf dem TCP-Server, um eingehende TCP-Segmente sofort zu bestätigen. Diese Problemumgehung funktioniert am besten in einer Umgebung mit einer großen Clientinstallationsbasis, in der Sie das Programmverhalten nicht ändern können. Für Szenarien, in denen der Remote-TCP-Server auf einem Windows-basierten Server ausgeführt wird, müssen Sie die Registrierung des Remoteservers ändern. Informationen zum Ändern des Zeitgebers für die verzögerte Bestätigung finden Sie in der Dokumentation des Betriebssystems.

Führen Sie auf einem Server mit Windows 2000 die folgenden Schritte aus:

  1. Starten Sie den Registrierungs-Editor (Regedit.exe).
  2. Suchen Sie den folgenden Registrierungsunterschlüssel, und klicken Sie darauf: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\<Interface GUID>
  3. Klicken Sie im Menü "Bearbeiten" auf "Wert hinzufügen", und erstellen Sie dann den folgenden Registrierungswert:
    Wertname: TcpDelAckTicks
    Datentyp: REG_DWORD
    Wertdaten: 0
  4. Beenden Sie den Registrierungs-Editor.
  5. Starten Sie Windows neu, damit diese Änderung wirksam wird.

Führen Sie auf einem Server mit Windows XP oder Windows Server 2003 die folgenden Schritte aus:

  1. Starten Sie den Registrierungs-Editor.
  2. Suchen Sie den folgenden Registrierungsunterschlüssel, und klicken Sie darauf: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\<Interface GUID>
  3. Zeigen Sie im Menü Bearbeiten auf Neu, und klicken Sie anschließend auf DWORD-Wert.
  4. Nennen Sie den neuen Wert "TcpAckFrequency", und weisen Sie ihm den Wert 1 zu.
  5. Beenden Sie den Registrierungs-Editor.
  6. Starten Sie Windows neu, damit diese Änderung wirksam wird.

Methode 4: Ändern des Pufferverhaltens in afd.sys für nicht blockierende Sockets

Wichtig

Dieser Abschnitt, diese Methode bzw. diese Aufgabe enthält eine Beschreibung der Schritte zum Bearbeiten der Registrierung. Durch die falsche Bearbeitung der Registrierung können schwerwiegende Probleme verursacht werden. Daher ist es wichtig, bei der Ausführung der folgenden Schritte sorgfältig vorzugehen. Für zusätzlichen Schutz sichern Sie die Registrierung, bevor Sie sie ändern. Sie können die Registrierung wiederherstellen, wenn ein Problem auftritt. Weitere Informationen zum Sichern und Wiederherstellen der Registrierung finden Sie in der folgenden Artikelnummer, um den Artikel in der Microsoft Knowledge Base zu sehen: 322756 Sichern und Wiederherstellen der Registrierung in Windows

Hinweis

Dieser Registrierungsschlüssel ist nur für Windows Server 2003 mit Service Pack 1 und nachfolgenden Service Packs verfügbar.

  1. Klicken Sie auf "Start", gebenregedit.exe ein, und klicken Sie dann auf "OK".
  2. Klicken Sie auf den folgenden Registrierungsunterschlüssel:
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\AFD\Parameters
  3. Zeigen Sie im Menü Bearbeiten auf Neu, und klicken Sie anschließend auf DWORD-Wert.
  4. Nennen Sie den neuen Wert "NonBlockingSendSpecialBuffering", und weisen Sie ihm den Wert 1 zu.
  5. Beenden Sie den Registrierungs-Editor.
  6. Starten Sie Windows neu, damit diese Änderung wirksam wird.

Status

Microsoft hat bestätigt, dass dies ein Problem in den Microsoft-Produkten ist, die im Abschnitt "Gilt für" aufgeführt sind.

Informationsquellen

328890 Neuer Registrierungseintrag zum Steuern des Verhaltens der TCP-Bestätigung (ACK) in Windows XP und Windows Server 2003