Ralentissement des performances se produit lorsque vous copiez des données vers un serveur TCP à l’aide d’un programme API Windows Sockets

S’applique à : Microsoft Windows Server 2003 Enterprise Edition (32-bit x86)Microsoft Windows Server 2003 Standard Edition (32-bit x86)Microsoft Windows Server 2003 Web Edition

Symptômes


Lorsque vous exécutez un programme qui utilise l’API Windows Sockets, vous pouvez rencontrer le ralentissement des performances lorsque vous copiez des données vers un serveur TCP.

Si vous effectuez un suivi du réseau avec un renifleur de réseau tel que moniteur réseau Microsoft, le serveur TCP envoie un accusé de réception de TCP de segment au dernier segment TCP dans un flux de données TCP de la minuterie d’accusé réception différé (également connu sous le nom du compteur ACK retardé). Par défaut, pour les systèmes d’exploitation Windows, la valeur de cette minuterie est 200 millisecondes (ms). Un flux de données standard pour l’envoi de 64 kilo-octets (Ko) de données est similaire à la séquence suivante :
Client->Server 1460 bytesClient->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 bytes
-> delayed ACK 200 ms



Cause


Ce problème se produit en raison du comportement d’architecture de l’API Windows Sockets et Afd.sys. Ce problème se produit si toutes les conditions suivantes sont remplies :

  • Le programme Windows Sockets utilise des sockets de non-bloquante.
  • Un appel d’un seul envoi ou WSASend remplit la mémoire tampon d’envoi socket sous-jacent ensemble.

    Par exemple, le programme utilise la fonction setsockopt de Windows Sockets pour modifier la mémoire tampon d’envoi par défaut socket 32 Ko au cours de ses routines d’initialisation de socket :
    setsockopt( sock, SOL_SOCKET, 32768, (char *) &val, sizeof( int ) );
    Ultérieurement, lorsque le programme envoie les données, il émet un appel de Envoyer ou WSASend et envoie de 64 Ko de données lors de chaque envoi :
    send(socket, pWrBuffer, 65536, 0);
    Dans ce scénario, chaque fois que les problèmes du programme un envoi appel de 64 Ko de données, le programme renvoie un code d’erreur SOCKET_ERROR si la mémoire tampon sous-jacente de socket de 32 Ko est complètement remplie. Une fois qu’il appelle la fonction WSAGetLastError , le programme reçoit le code d’erreur WSAEWOULDBLOCK . La plupart des programmes utilisent la fonction Sélectionner des Sockets Windows pour vérifier l’état du socket. Dans ce scénario, la fonction Sélectionner ne signale pas le socket comme accessibles en écriture jusqu'à ce que le client reçoit le segment TCP ACK en suspens. Par défaut, dans un environnement Windows, cette opération peut prendre jusqu'à 200 ms en raison de l’algorithme d’accusé réception différé.
  • Le serveur TCP distant reconnaît tous les segments TCP avant que le client envoie le dernier segment TCP avec le jeu de bits push.

Solution de contournement


Pour contourner ce problème, appliquez l’une des méthodes suivantes.

Méthode 1 : Utiliser les Sockets de blocage

Ce problème se produit uniquement avec les sockets de non-bloquante. Lorsque vous utilisez un socket bloquant, ce problème ne se produit pas car Afd.sys gère la mémoire tampon de socket différemment. Pour plus d’informations sur socket bloquant et non bloquante de programmation, consultez la documentation du Kit de développement de plate-forme Microsoft.

Méthode 2 : Vérifiez la taille de mémoire tampon d’envoi Socket supérieure à la taille de mémoire tampon d’envoi programme

Pour modifier la mémoire tampon d'envoi de la socket, utilisez d'abord la fonction getsockopt de Windows Sockets pour déterminer la taille du tampon (SO_SNDBUF) en cours puis utiliser la fonction setsockopt pour définir la nouvelle taille du tampon mémoire à envoyer. Lorsque vous avez terminé, la valeur SO_SNDBUF doit être supérieure à la taille de mémoire tampon d’envoi programme d’au moins 1 octet.

Modifiez l’appel de l’Envoyer ou l’appel de WSASend pour spécifier un tampon de taille inférieure à la valeur SO_SNDBUF d’au moins 1 octet. Dans l’exemple précédent dans la section « Cause » de cet article, vous pouvez modifier l’appel setsockopt à la valeur suivante,
setsockopt( sock, SOL_SOCKET, 65537, (char *) &val, sizeof( int ) );
ou bien, vous pouvez modifier l’appel à Envoyer à la valeur suivante :
send(socket, pWrBuffer, 32767, 0);
Vous pouvez également utiliser n’importe quelle combinaison de ces valeurs.

Méthode 3 : Modifier les paramètres TCP/IP sur le serveur TCP

Important Cette section, méthode ou tâche contient des étapes vous indiquant comment modifier le Registre. Toutefois, des problèmes graves peuvent survenir si vous modifiez le Registre de façon incorrecte. Par conséquent, veillez à suivre ces étapes scrupuleusement. Pour une meilleure protection, sauvegardez le Registre avant de le modifier. Vous pourriez alors restaurer le Registre si un problème survient. Pour plus d’informations sur la façon de sauvegarder et de restaurer le Registre, cliquez sur le numéro ci-dessous pour afficher l’article correspondant dans la Base de connaissances Microsoft :
322756 comment sauvegarder et restaurer le Registre dans Windows


Modifier les paramètres TCP/IP sur le serveur TCP immédiatement accuser réception des segments TCP entrants. Cette solution de contournement fonctionne mieux dans un environnement qui possède une base d’installation client volumineux et où vous ne pouvez pas modifier le déroulement du programme. Pour les scénarios où le serveur TCP distant s’exécute sur un serveur fonctionnant sous Windows, vous devez modifier le Registre du serveur distant. Pour les autres systèmes d’exploitation, consultez la documentation du système d’exploitation pour plus d’informations sur la modification de la minuterie d’accusé réception différé.

Sur un serveur qui exécute Windows 2000, procédez comme suit :
  1. Démarrez l'Éditeur du Registre (Regedit.exe).
  2. Recherchez et cliquez sur la sous-clé de Registre suivante :
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\ < GUID d’Interface >
  3. Dans le menu Edition , cliquez sur Ajouter une valeuret puis créer la valeur de Registre suivante :

    Nom de la valeur: TcpDelAckTicks
    Type de données: REG_DWORD
    Données de la valeur: 0
  4. Quittez l’Éditeur du Registre.
  5. Redémarrez Windows pour que cette modification prenne effet.
Sur un serveur qui exécute Windows XP ou Windows Server 2003, procédez comme suit :
  1. Démarrez l'Éditeur du Registre.
  2. Recherchez et cliquez sur la sous-clé de Registre suivante :
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\ < GUID d’Interface >
  3. Dans le menu Edition , pointez sur Nouveau, puis cliquez sur Valeur DWORD.
  4. Nommez la nouvelle valeur entrée TcpAckFrequencyet lui assigner une valeur de 1.
  5. Quittez l’Éditeur du Registre.
  6. Redémarrez Windows pour que cette modification prenne effet.

Méthode 4 : Modifier le comportement de mise en mémoire tampon dans Afd.sys pour les non-bloquante de sockets

Important Cette section, méthode ou tâche contient des étapes vous indiquant comment modifier le Registre. Toutefois, des problèmes graves peuvent survenir si vous modifiez le Registre de façon incorrecte. Par conséquent, veillez à suivre ces étapes scrupuleusement. Pour une meilleure protection, sauvegardez le Registre avant de le modifier. Vous pourriez alors restaurer le Registre si un problème survient. Pour plus d’informations sur la façon de sauvegarder et de restaurer le Registre, cliquez sur le numéro ci-dessous pour afficher l’article correspondant dans la Base de connaissances Microsoft :
322756 comment sauvegarder et restaurer le Registre dans Windows


Remarque Cette clé de Registre est uniquement disponible pour Windows Server 2003 avec Service Pack 1 et les service packs ultérieurs.
  1. Cliquez sur Démarrer, tapez regedit.exeet cliquez sur OK.
  2. Recherchez et cliquez sur la sous-clé de Registre suivante :
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\AFD\Parameters
  3. Dans le menu Edition , pointez sur Nouveau, puis cliquez sur Valeur DWORD.
  4. Nommez la nouvelle valeur NonBlockingSendSpecialBufferinget lui assigner une valeur de 1.
  5. Quittez l'Éditeur du Registre.
  6. Redémarrez Windows pour que cette modification prenne effet.

État


Microsoft a confirmé l'existence de ce problème dans les produits Microsoft répertoriés dans la section « S'applique à ».

Références


Nouvelle entrée de Registre 328890 pour contrôler le comportement d’accusé de réception TCP (ACK) dans Windows XP et dans Windows Server 2003