Le prestazioni rallentate si verificano quando si copiano dati in un server TCP usando un programma API Windows Sockets

Questo articolo fornisce soluzioni alternative per il problema in cui si verificano prestazioni lente quando si copiano dati in un server TCP usando un programma API Windows Sockets.

Si applica a: Windows Server 2012 R2, Windows 10 tutte le edizioni
Numero KB originale: 823764

Sintomi

Quando si esegue un programma che usa l'API Windows Sockets, è possibile che si verifichino prestazioni lente quando si copiano dati in un server TCP.

Se si esegue una traccia di rete con uno sniffer di rete, ad esempio Monitoraggio rete Microsoft, il server TCP invia un segmento TCP ACK all'ultimo segmento TCP in un flusso di dati TCP nel timer di riconoscimento ritardato (noto anche come timer ACK ritardato). Per impostazione predefinita, per i sistemi operativi Windows, il valore per questo timer è 200 millisecondi (ms). Un flusso di dati tipico per l'invio di 64 kilobyte (KB) di dati è simile alla sequenza seguente:

Client-Server> 1460 byte
Client-Server> 1460 byte
ACK server-client>
Client-Server> 1460 byte
Client-Server> 1460 byte
ACK server-client>
....
Client-Server> 1460 byte
Client-Server> 1460 byte
Server-Client> ACK-PUSH
Client-Server> 1296 byte
-> ACK ritardato di 200 ms

Causa

Questo problema si verifica a causa del comportamento architetturale dell'API Windows Sockets e afd.sys. Questo problema si verifica se tutte le condizioni seguenti sono vere:

  • Il programma Windows Sockets usa socket non bloccanti.

  • Una singola chiamata di invio o una chiamata WSASend riempie l'intero buffer di invio del socket sottostante.

    Ad esempio, il programma usa la funzione Windows Sockets setsockopt per modificare il buffer di invio socket predefinito a 32 KB durante le routine di inizializzazione del socket:

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

    In seguito, quando il programma invia dati, invia una chiamata di invio o una chiamata WSASend e invia 64 KB di dati durante ogni invio:

    send(socket, pWrBuffer, 65536, 0);
    

    In questo scenario, ogni volta che il programma invia una chiamata di invio di 64 KB di dati, il programma restituisce un codice di errore SOCKET_ERROR se viene riempito il buffer del socket sottostante da 32 KB. Dopo aver chiamato la funzione WSAGetLastError, il programma riceve il codice di errore WSAEWOULDBLOCK. La maggior parte dei programmi usa la funzione di selezione Windows Sockets per controllare lo stato del socket. In questo scenario, la funzione select non segnala il socket come scrivibile fino a quando il client non riceve il segmento ACK TCP in sospeso. Per impostazione predefinita in un ambiente Windows, l'operazione potrebbe richiedere fino a 200 ms a causa dell'algoritmo di riconoscimento ritardato.

  • Il server TCP remoto riconosce tutti i segmenti TCP prima che il client invii l'ultimo segmento TCP con il set di bit push.

Soluzione alternativa

Per risolvere questo problema, usare uno dei metodi seguenti.

Metodo 1: Usare socket di blocco

Questo problema si verifica solo con socket non bloccanti. Quando si usa un socket di blocco, questo problema non si verifica perché afd.sys gestisce il buffer del socket in modo diverso. Per altre informazioni sulla programmazione socket di blocco e non bloccante, vedere la documentazione di Microsoft Platform SDK.

Metodo 2: Rendere le dimensioni del buffer di invio del socket maggiori rispetto alle dimensioni del buffer di trasmissione del programma

Per modificare il buffer di trasmissione del socket, usare la funzione Windows Sockets getsockopt per determinare le dimensioni correnti del buffer di trasmissione del socket (SO_SNDBUF) e quindi usare la setsockopt funzione per impostare le dimensioni del buffer di trasmissione del socket. Al termine, il valore SO_SNDBUF deve essere maggiore di almeno 1 byte rispetto alle dimensioni del buffer di invio del programma.

Modificare la chiamata di invio o la chiamata WSASend per specificare una dimensione del buffer di almeno 1 byte inferiore al valore SO_SNDBUF. Nell'esempio precedente della sezione "Cause" di questo articolo è possibile modificare la chiamata setsockopt al valore seguente,

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

oppure è possibile modificare la chiamata di invio al valore seguente:

send(socket, pWrBuffer, 32767, 0);

È anche possibile usare qualsiasi combinazione di questi valori.

Metodo 3: Modificare le impostazioni TCP/IP nel server TCP

Importante

In questa sezione, metodo o attività viene illustrata la procedura per modificare il Registro di sistema. Poiché l'errata modifica del Registro di sistema può causare seri problemi, Di conseguenza, attenersi scrupolosamente alla procedura indicata. Per una maggiore protezione, eseguire il backup del Registro di sistema prima di modificarlo. In questo modo sarà possibile ripristinare il Registro di sistema se si verifica un problema. Per ulteriori informazioni sull'esecuzione del backup e del ripristino del Registro di sistema, fare clic sul numero dell'articolo della Microsoft Knowledge Base riportato di seguito:
322756 Come eseguire il backup e il ripristino del Registro di sistema in Windows

Modificare le impostazioni TCP/IP nel server TCP per confermare immediatamente i segmenti TCP in ingresso. Questa soluzione alternativa funziona meglio in un ambiente con una base di installazione client di grandi dimensioni e in cui non è possibile modificare il comportamento del programma. Per gli scenari in cui il server TCP remoto viene eseguito in un server basato su Windows, è necessario modificare il registro del server remoto. Per altri sistemi operativi, vedere la documentazione del sistema operativo per informazioni su come modificare il timer di riconoscimento ritardato.

In un server che esegue Windows 2000 seguire questa procedura:

  1. Avviare Editor del Registro di sistema (Regedit.exe).
  2. Individuare e selezionare la seguente sottochiave del Registro di sistema: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\<Interface GUID>
  3. Nel menu Modifica fare clic su Aggiungi valore e quindi creare il valore del Registro di sistema seguente:
    Nome valore: TcpDelAckTicks
    Tipo di dati: REG_DWORD
    Dati valore: 0
  4. Chiudere l'editor del Registro di sistema.
  5. Riavviare Windows per rendere effettiva questa modifica.

In un server che esegue Windows XP o Windows Server 2003 seguire questa procedura:

  1. Avviare l'editor del Registro di sistema.
  2. Individuare e selezionare la seguente sottochiave del Registro di sistema: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\<Interface GUID>
  3. Scegliere Nuovo dal menu Modifica, quindi fare clic su Valore DWORD.
  4. Assegnare al nuovo valore il nome TcpAckFrequency e assegnargli il valore 1.
  5. Chiudere l'editor del Registro di sistema.
  6. Riavviare Windows per rendere effettiva questa modifica.

Metodo 4: Modificare il comportamento di buffering in afd.sys per i socket non bloccanti

Importante

In questa sezione, metodo o attività viene illustrata la procedura per modificare il Registro di sistema. Poiché l'errata modifica del Registro di sistema può causare seri problemi, Di conseguenza, attenersi scrupolosamente alla procedura indicata. Per una maggiore protezione, eseguire il backup del Registro di sistema prima di modificarlo. In questo modo sarà possibile ripristinare il Registro di sistema se si verifica un problema. Per altre informazioni su come eseguire il backup e il ripristino del Registro di sistema, fare clic sul numero dell'articolo della Microsoft Knowledge Base seguente: 322756 Come eseguire il backup e ripristinare il Registro di sistema in Windows

Nota

Questa chiave del Registro di sistema è disponibile solo per Windows Server 2003 con Service Pack 1 e i Service Pack successivi.

  1. Fare clic su Start, digitare regedit.exee quindi fare clic su OK.
  2. Individuare e selezionare la seguente sottochiave del Registro di sistema:
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\AFD\Parameters
  3. Scegliere Nuovo dal menu Modifica, quindi fare clic su Valore DWORD.
  4. Assegnare al nuovo valore il nome NonBlockingSendSpecialBuffering e assegnargli il valore 1.
  5. Uscire dalla Editor del Registro di sistema.
  6. Riavviare Windows per rendere effettiva questa modifica.

Stato

Microsoft ha confermato che questo problema si verifica nei prodotti elencati nella sezione "Si applica a".

Riferimenti

328890 Nuova voce del Registro di sistema per il controllo del comportamento tcp acknowledgment (ACK) in Windows XP e in Windows Server 2003