SYMPTOMS
When you run a program that uses the Windows Sockets API, you may experience slow performance when you copy data to a TCP server.
If you make a network trace with a network sniffer such as Microsoft Network Monitor, the TCP server sends a TCP ACK segment to the last TCP segment in a TCP data stream in the delayed acknowledgement timer (also known as the delayed ACK timer). By default, for Windows operating systems, the value for this timer is 200 milliseconds (ms). A typical data flow for sending 64 kilobytes (KB) of data looks similar to the following sequence:
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 bytes
-> delayed ACK 200 ms
WORKAROUND
To work around this problem, use any of the following methods.
Method 1: Use Blocking Sockets
This problem only occurs with non-blocking sockets. When you use a blocking socket, this problem does not occur because Afd.sys handles the socket buffer differently. For more information about blocking and non-blocking socket programming, see the Microsoft Platform SDK documentation.
Method 2: Make the Socket Send Buffer Size Larger Than the Program Send Buffer Size
To modify the socket send buffer, use the Windows Sockets
getsockopt function to determine the current socket send buffer size (SO_SNDBUF), and then use the
setsockopt function to set the socket send buffer size. When you are finished, the SO_SNDBUF value must be at least 1 byte larger than the program send buffer size.
Modify the
send call or the
WSASend call to specify a buffer size at least 1 byte smaller than the SO_SNDBUF value. In the earlier example in the "Cause" section of this article, you could modify the
setsockopt call to the following value,
setsockopt( sock, SOL_SOCKET, 65537, (char *) &val, sizeof( int ) );
or you could modify the
send call to the following value:
send(socket, pWrBuffer, 32767, 0);
You could also use any combination of these values.
Method 3: Modify the TCP/IP Settings on the TCP Server
WARNING: If you use Registry Editor incorrectly, you may cause serious problems that may require you to reinstall your operating system. Microsoft cannot guarantee that you can solve problems that result from using Registry Editor incorrectly. Use Registry Editor at your own risk.
Modify the TCP/IP settings on the TCP server to immediately acknowledge incoming TCP segments. This workaround works best in an environment that has a large client installation base and where you cannot change the program's behavior. For scenarios where the remote TCP server runs on a Windows-based server, you must modify the registry of the remote server. For other operating systems, see the operating system's documentation for information about how to change the delayed acknowledgement timer.
On a server that runs Windows 2000, follow these steps:
- Start Registry Editor (Regedit.exe).
- Locate and then click the following registry subkey:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\<Interface GUID>
- On the Edit menu, click Add Value, and then create the following registry value:
Value name: TcpDelAckTicks
Data type: REG_DWORD
Value data: 0 - Quit Registry Editor.
- Restart Windows for this change to take effect.
On a server that runs Windows XP or Windows Server 2003, follow these steps:
- Start Registry Editor.
- Locate and then click the following registry subkey:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\<Interface GUID>
- On the Edit menu, point to New, and then click DWORD Value.
- Name the new value TcpAckFrequency, and assign it a value of 1.
- Quit Registry Editor.
- Restart Windows for this change to take effect.
Method 4: Modify the buffering behavior in Afd.sys for non-blocking sockets
WARNING: If you use Registry Editor incorrectly, you may cause serious problems that may require you to reinstall your operating system. Microsoft cannot guarantee that you can solve problems that result from using Registry Editor incorrectly. Use Registry Editor at your own risk.
Note This registry key is only available for Windows Server 2003 with Service Pack 1 and subsequent service packs.
- Click Start, type regedit.exe, and then click OK.
- Locate and then click the following registry subkey:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\AFD\Parameters
- On the Edit menu, click Add Value, and then create the following registry value:
Value name: NonBlockingSendSpecialBuffering
Data type: REG_DWORD
Value data: 1 - Exit Registry Editor.
- Restart Windows for this change to take effect.