도메인 컨트롤러 열거
이전 버전의 Windows에서는 애플리케이션이 DsGetDcName을 호출하여 도메인에서 단일 도메인 컨트롤러만 가져올 수 있었습니다. 검색할 도메인 컨트롤러를 예측하거나 도메인 컨트롤러 목록을 가져올 방법이 없었습니다. Windows를 사용하면 애플리케이션이 DsGetDcOpen, DsGetDcNext 및 DsGetDcClose 함수를 사용하여 도메인의 도메인 컨트롤러를 열거할 수 있습니다.
도메인 컨트롤러를 열거하려면 DsGetDcOpen을 호출합니다. 이 함수는 열거할 도메인 및 기타 열거형 옵션을 정의하는 매개 변수를 사용합니다. DsGetDcOpen 은 DsGetDcNext 및 DsGetDcClose 가 호출되는 경우 열거형 작업을 식별하는 데 사용되는 도메인 열거형 컨텍스트 핸들 을 제공합니다.
DsGetDcNext 함수는 열거형에서 다음 도메인 컨트롤러를 검색하기 위해 도메인 열거형 컨텍스트 핸들을 사용하여 호출됩니다. 이 함수가 처음 호출될 때 열거형의 첫 번째 도메인 컨트롤러가 검색됩니다. 이 함수가 두 번째로 호출될 때 열거형의 두 번째 도메인 컨트롤러가 검색됩니다. 이 프로세스는 DsGetDcNext 가 열거형의 끝을 나타내는 ERROR_NO_MORE_ITEMS 반환할 때까지 반복됩니다.
DsGetDcNext 함수는 도메인 컨트롤러를 두 그룹으로 열거합니다. 첫 번째 그룹에는 함수가 실행되는 컴퓨터의 사이트를 포함하는 도메인 컨트롤러가 포함되고 두 번째 그룹에는 함수가 실행되는 컴퓨터의 사이트를 다루지 않는 도메인 컨트롤러가 포함됩니다. DS_NOTIFY_AFTER_SITE_RECORDS 플래그가 DsGetDcOpen의 OptionFlags 매개 변수에 지정된 경우 DsGetDcNext 함수는 모든 사이트별 도메인 컨트롤러를 검색한 후 ERROR_FILEMARK_DETECTED 반환합니다. 그런 다음 DsGetDcNext는 첫 번째 그룹에 포함된 사이트별 도메인 컨트롤러를 포함하여 도메인의 모든 도메인 컨트롤러를 포함하는 두 번째 그룹을 열거하기 시작합니다.
함수가 실행되는 컴퓨터의 사이트를 처리하는 도메인 컨트롤러가 먼저 열거되고 함수가 실행되는 컴퓨터의 사이트를 다루지 않는 도메인 컨트롤러가 먼저 열거됩니다. 도메인 컨트롤러는 도메인 컨트롤러가 해당 사이트에 상주하도록 구성되어 있거나 도메인 컨트롤러가 구성된 사이트 간 링크 비용 측면에서 해당 사이트에 가장 가까운 사이트에 있는 경우 사이트를 커버한다고 합니다. 포함하는 도메인 컨트롤러 그룹과 컴퓨터 사이트를 다루지 않는 도메인 컨트롤러 그룹 모두에 도메인 컨트롤러가 있는 경우 도메인 컨트롤러는 DNS에 지정된 구성된 우선 순위 및 가중치 순으로 그룹 내에서 반환됩니다. 숫자 우선 순위가 낮은 도메인 컨트롤러는 먼저 그룹 내에서 반환됩니다. 사이트 관련 그룹 내에 동일한 우선 순위를 가진 여러 도메인 컨트롤러의 하위 그룹이 있는 경우 도메인 컨트롤러는 가중치가 더 높은 도메인 컨트롤러가 먼저 반환될 확률이 더 높은 가중치 임의 순서로 반환됩니다. 사이트, 우선 순위 및 가중치는 도메인 관리자가 도메인에서 사용할 수 있는 여러 도메인 컨트롤러 간에 효과적인 성능 및 부하 분산을 달성하도록 구성됩니다. 이 때문에 DsGetDcOpen/DsGetDcNext/DsGetDcClose 함수를 사용하는 애플리케이션은 이러한 최적화를 자동으로 활용합니다.
열거형이 완료되거나 더 이상 필요하지 않은 경우 도메인 열거형 컨텍스트 핸들을 사용하여 DsGetDcClose 를 호출하여 열거형을 닫아야 합니다.
열거형을 다시 설정하려면 DsGetDcClose 를 호출하여 현재 열거형을 닫은 다음 DsGetDcOpen 을 다시 호출하여 열거형을 다시 열어야 합니다.
예제
다음 코드 예제에서는 이러한 함수를 사용하여 로컬 도메인의 도메인 컨트롤러를 열거하는 방법을 보여 줍니다.
DWORD dwRet;
PDOMAIN_CONTROLLER_INFO pdcInfo;
// Get a domain controller for the domain this computer is on.
dwRet = DsGetDcName(NULL, NULL, NULL, NULL, 0, &pdcInfo);
if(ERROR_SUCCESS == dwRet)
{
HANDLE hGetDc;
// Open the enumeration.
dwRet = DsGetDcOpen( pdcInfo->DomainName,
DS_NOTIFY_AFTER_SITE_RECORDS,
NULL,
NULL,
NULL,
0,
&hGetDc);
if(ERROR_SUCCESS == dwRet)
{
LPTSTR pszDnsHostName;
/*
Enumerate each domain controller and print its name to the
debug window.
*/
while(TRUE)
{
ULONG ulSocketCount;
LPSOCKET_ADDRESS rgSocketAddresses;
dwRet = DsGetDcNext(
hGetDc,
&ulSocketCount,
&rgSocketAddresses,
&pszDnsHostName);
if(ERROR_SUCCESS == dwRet)
{
OutputDebugString(pszDnsHostName);
OutputDebugString(TEXT("\n"));
// Free the allocated string.
NetApiBufferFree(pszDnsHostName);
// Free the socket address array.
LocalFree(rgSocketAddresses);
}
else if(ERROR_NO_MORE_ITEMS == dwRet)
{
// The end of the list has been reached.
break;
}
else if(ERROR_FILEMARK_DETECTED == dwRet)
{
/*
DS_NOTIFY_AFTER_SITE_RECORDS was specified in
DsGetDcOpen and the end of the site-specific
records was reached.
*/
OutputDebugString(
TEXT("End of site-specific domain controllers\n"));
continue;
}
else
{
// Some other error occurred.
break;
}
}
// Close the enumeration.
DsGetDcClose(hGetDc);
}
// Free the DOMAIN_CONTROLLER_INFO structure.
NetApiBufferFree(pdcInfo);
}