Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Questo articolo offre soluzioni alternative per il problema a causa del quale si verificano lente prestazioni quando si copiano dati in un server TCP usando un programma API Windows Sockets.
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 crea una traccia di rete con uno sniffer di rete, ad esempio Microsoft Network Monitor, 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
Server-Client> ACK
Client-Server> 1460 byte
Client-Server> 1460 byte
Server-Client> ACK
....
Client-Server> 1460 byte
Client-Server> 1460 byte
Server-Client> ACK-PUSH
Client-Server> 1296 byte
-> ritardato ACK 200 ms
Causa
Questo problema si verifica a causa del comportamento dell'architettura 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 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 del socket predefinito a 32 KB durante le routine di inizializzazione del socket:setsockopt( sock, SOL_SOCKET, 32768, (char *) &val, sizeof( int ));
Successivamente, 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 emette 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 da 32 KB sottostante. Dopo aver chiamato la funzione WSAGetLastError, il programma riceve il codice di errore WSAEWOULDBLOCK. La maggior parte dei programmi usa la funzione di selezione di 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 TCP ACK in sospeso. Per impostazione predefinita in un ambiente Windows, questa operazione può 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, utilizzare 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 sul blocco e sulla programmazione dei socket non bloccatori, vedere la documentazione di Microsoft Platform SDK.
Metodo 2: aumentare le dimensioni del buffer di invio del socket rispetto alle dimensioni del buffer di invio del programma
Per modificare il buffer di invio del socket, usare la funzione Windows Sockets getsockopt
per determinare la dimensione corrente 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 nella sezione "Causa" 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. Se, tuttavia, si modifica il Registro di sistema in modo errato, possono verificarsi gravi problemi. Pertanto, assicurarsi di osservare attentamente la procedura seguente. Per una maggiore protezione, eseguire il backup del Registro di sistema prima di modificarlo. Successivamente, è possibile ripristinare il Registro di sistema se si verifica un problema. Per ulteriori informazioni su come eseguire il backup e il ripristino del registro, fare clic sul numero dell'articolo seguente per visualizzare l'articolo nella Microsoft Knowledge Base:
322756 Come eseguire il backup e il ripristino del registro 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 di sistema 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:
- Avviare l'editor del Registro di sistema (Regedit.exe).
- Individuare e selezionare la seguente sottochiave del Registro di sistema:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\<Interface GUID>
- Scegliere Aggiungi valore dal menu Modifica e quindi creare il valore del Registro di sistema seguente:
Nome valore: TcpDelAckTicks
Tipo di dati: REG_DWORD
Dati valore: 0 - Chiudere l'editor del Registro di sistema.
- Riavviare Windows per rendere effettiva questa modifica.
In un server che esegue Windows XP o Windows Server 2003, seguire questa procedura:
- Avviare l'editor del Registro di sistema.
- Individuare e selezionare la seguente sottochiave del Registro di sistema:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\<Interface GUID>
- Scegliere Nuovo dal menu Modifica, quindi fare clic su Valore DWORD.
- Denominare il nuovo valore TcpAckFrequency e assegnargli un valore pari a 1.
- Chiudere l'editor del Registro di sistema.
- 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. Se, tuttavia, si modifica il Registro di sistema in modo errato, possono verificarsi gravi problemi. Pertanto, assicurarsi di osservare attentamente la procedura seguente. Per una maggiore protezione, eseguire il backup del Registro di sistema prima di modificarlo. Successivamente, è 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 di articolo seguente per visualizzare l'articolo della Microsoft Knowledge Base: 322756 Come eseguire il backup e ripristinare il Registro di sistema in Windows
Note
Questa chiave del Registro di sistema è disponibile solo per Windows Server 2003 con Service Pack 1 e i Service Pack successivi.
- Fare clic su Start, digitare regedit.exe e quindi fare clic su OK.
- Individuare e selezionare la seguente sottochiave del Registro di sistema:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\AFD\Parameters
- Scegliere Nuovo dal menu Modifica, quindi fare clic su Valore DWORD.
- Denominare il nuovo valore NonBlockingSendSpecialBuffering e assegnargli un valore pari a 1.
- Uscire dall'editor del Registro di sistema.
- 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 controllare il comportamento del riconoscimento TCP (ACK) in Windows XP e in Windows Server 2003