Windows 소켓 API 프로그램을 사용하여 TCP 서버에 데이터를 복사할 때 성능 저하가 발생합니다.

이 문서에서는 Windows 소켓 API 프로그램을 사용하여 TCP 서버에 데이터를 복사할 때 성능 저하가 발생하는 문제에 대한 해결 방법을 제공합니다.

적용 대상: Windows Server 2012 R2, Windows 10 - 모든 버전
원본 KB 번호: 823764

증상

Windows 소켓 API를 사용하는 프로그램을 실행하는 경우 TCP 서버에 데이터를 복사할 때 성능이 저하될 수 있습니다.

Microsoft 네트워크 모니터와 같은 네트워크 스니퍼를 사용하여 네트워크 추적을 만드는 경우 TCP 서버는 TCP ACK 세그먼트를 지연된 승인 타이머(지연된 ACK 타이머라고도 함)의 TCP 데이터 스트림에 있는 마지막 TCP 세그먼트로 보냅니다. 기본적으로 Windows 운영 체제의 경우 이 타이머의 값은 200밀리초(밀리초)입니다. 64KB(KB)의 데이터를 보내는 일반적인 데이터 흐름은 다음 시퀀스와 유사합니다.

Client-Server> 1460바이트
Client-Server> 1460바이트
Server-Client> ACK
Client-Server> 1460바이트
Client-Server> 1460바이트
Server-Client> ACK
....
Client-Server> 1460바이트
Client-Server> 1460바이트
Server-Client> ACK-PUSH
Client-Server> 1296바이트
-> 지연된 ACK 200ms

원인

이 문제는 Windows 소켓 API 및 afd.sys 아키텍처 동작으로 인해 발생합니다. 이 문제는 다음 조건이 모두 충족되면 발생합니다.

  • Windows 소켓 프로그램은 비 차단 소켓을 사용합니다.

  • 단일 송신 호출 또는 WSASend 호출은 전체 기본 소켓 송신 버퍼를 채웁니다.

    예를 들어 프로그램은 Windows Sockets setsockopt 함수를 사용하여 소켓 초기화 루틴 중에 기본 소켓 송신 버퍼를 32KB로 변경합니다.

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

    나중에 프로그램이 데이터를 보내면 송신 전화 또는 WSASend 호출을 실행하고 각 전송 중에 64KB의 데이터를 보냅니다.

    send(socket, pWrBuffer, 65536, 0);
    

    이 시나리오에서는 프로그램에서 64KB의 데이터 보내기 호출을 발행할 때마다 기본 32KB 소켓 버퍼가 채워진 경우 프로그램에서 SOCKET_ERROR 오류 코드를 반환합니다. WSAGetLastError 함수를 호출하면 프로그램에서 WSAEWOULDBLOCK 오류 코드를 받습니다. 대부분의 프로그램은 Windows 소켓 선택 함수를 사용하여 소켓의 상태 검사. 이 시나리오에서 select 함수는 클라이언트가 미해결 TCP ACK 세그먼트를 받을 때까지 소켓을 쓰기 가능으로 보고하지 않습니다. 기본적으로 Windows 환경에서는 승인 알고리즘이 지연되어 200ms 정도 걸릴 수 있습니다.

  • 원격 TCP 서버는 클라이언트가 푸시 비트가 설정된 마지막 TCP 세그먼트를 보내기 전에 모든 TCP 세그먼트를 승인합니다.

해결 방법

이 문제를 해결하려면 다음 방법 중 일부를 사용합니다.

방법 1: 차단 소켓 사용

이 문제는 비 차단 소켓에서만 발생합니다. 차단 소켓을 사용하는 경우 afd.sys 소켓 버퍼를 다르게 처리하므로 이 문제가 발생하지 않습니다. 차단 및 비차단 소켓 프로그래밍에 대한 자세한 내용은 Microsoft Platform SDK 설명서를 참조하세요.

방법 2: 소켓 송신 버퍼 크기를 프로그램 송신 버퍼 크기보다 크게 만들기

소켓 보내기 버퍼를 수정하려면 Windows Sockets getsockopt 함수를 사용하여 현재 소켓 보내기 버퍼 크기(SO_SNDBUF)를 확인한 다음, 함수를 사용하여 setsockopt 소켓 송신 버퍼 크기를 설정합니다. 완료되면 SO_SNDBUF 값이 프로그램 송신 버퍼 크기보다 1 바이트 이상 커야 합니다.

보내기 호출 또는 WSASend 호출을 수정하여 버퍼 크기를 SO_SNDBUF 값보다 1바이트 이상 작게 지정합니다. 이 문서의 "원인" 섹션의 앞부분 예제에서 setsockopt 호출을 다음 값으로 수정할 수 있습니다.

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

또는 다음 값으로 보내기 호출을 수정할 수 있습니다.

send(socket, pWrBuffer, 32767, 0);

이러한 값의 조합을 사용할 수도 있습니다.

방법 3: TCP 서버에서 TCP/IP 설정 수정

중요

이 절, 방법 또는 작업에는 레지스트리를 수정하는 방법에 대한 단계가 포함되어 있습니다. 그러나 레지스트리를 잘못 수정하면 심각한 문제가 발생할 수 있습니다. 따라서 다음 단계를 주의하여 수행해야 합니다. 추가된 보호를 위해 레지스트리를 수정하기 전에 백업하세요. 그런 다음 문제가 발생할 경우 레지스트리를 복원할 수 있습니다. Windows XP 및 Windows Server 2003에서 레지스트리를 백업, 편집 및 복원하는 방법에 대한 자세한 내용은 다음 문서 번호를 클릭하여 Microsoft 기술 자료를 참조하세요.
322756 Windows에서 레지스트리를 백업 및 복원하는 방법

들어오는 TCP 세그먼트를 즉시 승인하도록 TCP 서버의 TCP/IP 설정을 수정합니다. 이 해결 방법은 대규모 클라이언트 설치 기반이 있고 프로그램의 동작을 변경할 수 없는 환경에서 가장 잘 작동합니다. 원격 TCP 서버가 Windows 기반 서버에서 실행되는 시나리오의 경우 원격 서버의 레지스트리를 수정해야 합니다. 다른 운영 체제의 경우 지연된 승인 타이머를 변경하는 방법에 대한 자세한 내용은 운영 체제 설명서를 참조하세요.

Windows 2000을 실행하는 서버에서 다음 단계를 수행합니다.

  1. 레지스트리 편집기(Regedit.exe)를 시작합니다.
  2. 다음 레지스트리 하위 키를 찾아서 클릭합니다. HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\<Interface GUID>
  3. 편집 메뉴에서 값 추가를 클릭한 다음 다음 레지스트리 값을 만듭니다.
    값 이름: TcpDelAckTicks
    데이터 형식: REG_DWORD
    값 데이터: 0
  4. 레지스트리 편집기를 종료합니다.
  5. 이 변경 내용이 적용되려면 Windows를 다시 시작합니다.

Windows XP 또는 Windows Server 2003을 실행하는 서버에서 다음 단계를 수행합니다.

  1. 레지스트리 편집기를 시작합니다.
  2. 다음 레지스트리 하위 키를 찾아서 클릭합니다. HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\<Interface GUID>
  3. 편집 메뉴에서 새로 만들기를 가리킨 다음 DWORD 값을 클릭합니다.
  4. 새 값의 이름을 TcpAckFrequency로 지정하고 값 1을 할당합니다.
  5. 레지스트리 편집기를 종료합니다.
  6. 이 변경 내용이 적용되려면 Windows를 다시 시작합니다.

방법 4: 비 차단 소켓에 대한 afd.sys 버퍼링 동작 수정

중요

이 절, 방법 또는 작업에는 레지스트리를 수정하는 방법에 대한 단계가 포함되어 있습니다. 그러나 레지스트리를 잘못 수정하면 심각한 문제가 발생할 수 있습니다. 따라서 다음 단계를 주의하여 수행해야 합니다. 추가된 보호를 위해 레지스트리를 수정하기 전에 백업하세요. 그런 다음 문제가 발생할 경우 레지스트리를 복원할 수 있습니다. 레지스트리를 백업하고 복원하는 방법에 대한 자세한 내용은 다음 문서 번호를 클릭하여 Microsoft 기술 자료: 322756 Windows에서 레지스트리를 백업 및 복원하는 방법 문서를 확인합니다.

참고

이 레지스트리 키는 서비스 팩 1 및 후속 서비스 팩이 있는 Windows Server 2003에서만 사용할 수 있습니다.

  1. 시작을 클릭하고 regedit.exe입력한 다음 확인을 클릭합니다.
  2. 다음 레지스트리 하위 키를 찾아서 클릭합니다.
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\AFD\Parameters
  3. 편집 메뉴에서 새로 만들기를 가리킨 다음 DWORD 값을 클릭합니다.
  4. 새 값의 이름을 NonBlockingSendSpecialBuffering으로 지정하고 값 1을 할당합니다.
  5. 레지스트리 편집기 종료합니다.
  6. 이 변경 내용이 적용되려면 Windows를 다시 시작합니다.

상태

Microsoft는 "적용 대상" 섹션에 있는 Microsoft 제품에 문제가 있다는 것을 확인했습니다.

참조

328890 Windows XP 및 Windows Server 2003에서 ACK(TCP 승인) 동작을 제어하기 위한 새로운 레지스트리 항목