WinHTTP 개요
이 주제에서는 Microsoft GDK(게임 개발 키트) 타이틀에 대해 Windows HTTP 서비스(WinHTTP) 기능을 사용하는 방법에 대해 설명합니다. PC 및 Xbox 콘솔 Microsoft GDK(게임 개발 키트) 타이틀에 사용할 수 있는 하위 수준의 HTTP 클라이언트 API입니다. 이를 사용하여 일반 HTTP 및 WebSocket 서비스 엔드포인트를 만들 수 있습니다.
하위 수준이므로 타이틀에 대해 안전하고 강력한 통신을 제공할 수 있도록 구현할 추가 고려 사항 및 단계가 있습니다. 타이틀 구현은 모든 통신 보안 모범 사례(NDA 항목)권한 부여 필요를 준수하는 것이 좋습니다.
WinHTTP 버전 차이
일반적으로 Microsoft GDK(게임 개발 키트) 타이틀은 Win32 응용 프로그램에서 WinHTTP와 상호 작용하는 것과 동일한 방식으로 WinHTTP와 상호 작용합니다.
Microsoft GDK(게임 개발 키트) 타이틀용으로 개발할 때 WinHTTP용 플랫 C/C++ API만 사용할 수 있습니다. 즉, 이 HTTP 클라이언트 API에서 HTTP 기능을 빌드해야 합니다.
Xbox 콘솔 프로젝트에 WinHTTP 추가
콘솔에 있는 소스 파일에서 #include <winhttp.h>
작업을 실시해야 합니다.
Winhttp.lib
에 직접 연결하는 것이 아니라 XGamePlatform.lib
에 연결해야 합니다.
WINAPI_PARTITION_GAMES
API 제품군의 API만 Microsoft GDK(Game Development Kit) 타이틀에서 작동합니다. Windows PC에서 Winhttp.lib
에 계속해서 연결해야 합니다.
WinHTTP를 Microsoft GDK(Game Development Kit) 타이틀에 통합하는 방법의 예는 SimpleWinHttp 샘플을 참조하세요. 자체 WinHTTP 구현에 대한 완벽한 호환 시작점을 제공하며 WinHttpManager
클래스를 포함합니다. 간단한 비동기 API 표면을 노출합니다.
네트워크 초기화 및 WinHTTP
WinHttpOpen을 처음 호출하기 전에 Microsoft GDK(Game Development Kit) 타이틀은 네트워킹 스택이 초기화되었는지 확인해야 합니다. 타이틀 시작 과정에서 WinHttpOpen
이(가) 너무 일찍 호출되면 WinHttpOpen
또는 후속 WinHTTP 호출이 실패하거나 불확실한 방식으로 충돌할 수 있습니다. 네트워크가 초기화되었다고 선언되기 전에는 요청이 성공한 것처럼 보이지만 실제로는 실패하거나, 그 반대 현상이 나타날 수 있습니다. 네트워킹 스택이 초기화되는 시기를 결정하는 방법에 대한 자세한 내용은 네트워크 초기화 및 연결을 참조하세요.
타이틀 일시 중지/재개와 WinHTTP
타이틀 일시 중지 알림을 받으면, 타이틀은 모든 WinHTTP 핸들을 닫는 프로세스를 시작해야 합니다. WinHTTP 핸들 정리는 비동기식입니다. 따라서 모든 요청 핸들, 모든 연결 핸들, 모든 세션 핸들 순으로 핸들을 닫아야 합니다. 윈의 비동기적 성격HTTP 핸들 정리는 알림 스레딩의 안전을 보장하기 위한 것입니다. 비동기식임에도 불구하고 WinHTTP 핸들 정리는 일정 기간 동안 지연되지 않습니다. 이렇게 하면 1초의 일시 중단-지연 제한 시간 안으로 쉽게 맞출 수 있습니다.
재개했을 때 타이틀은 네트워크 초기화 및 WinHTTP에 설명된 동일한 절차를 따르고, WinHTTP 사용을 계속하기 전에 네트워크가 준비 상태로 다시 돌아가기를 기다립니다. 중단과 재개 이벤트 사이에 오랜 시간이 지나면 WinHTTP API가 다시 확실한 상태가 되기 전에 네트워크가 다시 안정을 찾을 필요가 있습니다.
메모리 및 동시성 고려 사항
동시 WinHTTP 요청 수는 WinHTTP 내의 비동기 상태가 올바르게 작동하고 메모리 예산 내에서 작동하도록 항상 8개 미만으로 유지해야 합니다. 이 제한은 Xbox 서비스 API 및 XCurl
의 호출을 포함하여 타이틀 런타임 내의 모든 동시 작업에 적용됩니다.
WinSock 메모리 고려 사항에 대한 확장으로, 데이터를 수신할 때 가능한 한 빨리 커널 모드 메모리 풀에서 사용자 모드 프로세스로 데이터를 전송하고 HTTP 작업에 사용되는 커널 메모리 양을 최소화하기 위해 항상 WinHttpReadData
이(가) 있는 보류 중인 버퍼가 있는지(또는 WinHttpQueryDataAvailable
호출에서 콜백을 기다리고 있는지) 확인해야 합니다.
WinHttpQueryHeaders
getter 함수에는 일시적인 메모리 할당이 필요합니다. 내부 사용을 위해 lpdwBufferLength
매개 변수와 동일한 크기의 스크래치 버퍼를 할당하고 함수가 반환되기 전에 해제합니다. 따라서 WINHTTP_NO_OUTPUT_BUFFER
이중 호출 패턴을 사용하여 스크래치 버퍼 크기를 최소화하고 한 번에 WinHttpQueryHeaders
에 대한 동시 호출 수를 제한하여 시스템이 불안정해질 수 있는 과도한 시스템 메모리 사용을 방지해야 합니다. 헤더의 기본 최대 크기는 WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE
WinHTTP 옵션에 지정된 대로 64KB입니다.
WinHttpOpen 고려 사항
Flags
다음 표의 플래그를 WinHttpOpen에 전달해야 합니다.
매개 변수 | 값 |
---|---|
dwAccessType |
WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY |
pszProxyW |
WINHTTP_NO_PROXY_NAME |
pszProxyBypassW |
WINHTTP_NO_PROXY_BYPASS |
dwFlags |
WINHTTP_FLAG_SECURE_DEFAULTS |
WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY
, WINHTTP_NO_PROXY_NAME
, WINHTTP_NO_PROXY_BYPASS
의 결합을 이용하면 Microsoft GDK(게임 개발 키트) 플랫폼은 Fiddler 같은 프록시와 기타 극단적인 네트워킹 환경을 자동으로 처리합니다.
WINHTTP_FLAG_SECURE_DEFAULTS
플래그는 Microsoft GDK(게임 개발 키트) 타이틀이 권장 보안 연결 동작을 설정하여 보안 모범 사례를 준수하도록 특별히 설계된 새로운 플래그입니다. Xbox One 콘솔에서 사용할 수 있으며 향후 Windows OS 업데이트를 통해 데스크톱에서도 지원될 예정입니다.
WINHTTP_FLAG_SECURE_DEFAULTS
을(를) 기존 Windows OS 버전에서 전달하려고 하면 잘못된 매개 변수 오류가 발생합니다. 이 플래그에는 상당한 부작용이 있습니다. 이 플래그는 암시적으로 WINHTTP_FLAG_ASYNC
플래그를 포함하기 때문에 WinHTTP를 비동기 모드로 강제 전환합니다. 이 플래그를 지원하지 않는 Windows PC OS 버전에서는 나머지 WinHTTP 구현의 차이를 최소화하기 위해 WINHTTP_FLAG_ASYNC
을(를) 대신 통과해야 합니다.
참고 항목
WINHTTP_FLAG_SECURE_DEFAULTS
플래그를 사용하려면 WinHttpOpenRequest
에 전달된 일치하는 WINHTTP_FLAG_SECURE
플래그가 필요하며 암호화되지 않은 HTTP 요청은 차단됩니다. 내부 디버깅 및 테스트를 위한 개발 키트에서 추가 WinHTTP 세션 처리를 생성하고 WINHTTP_FLAG_ASYNC
플래그를 WinHttpOpen
에 지정할 수 있습니다. 그러면 WINHTTP_FLAG_SECURE
플래그를 WinHttpOpenRequest
에 지정하지 않고 개발 중에 암호화되지 않은 HTTP 요청을 만들 수 있습니다. 디버그가 아닌 트래픽에 대해 WINHTTP_FLAG_SECURE_DEFAULTS
(으)로 열린 세션 핸들을 여전히 RETAIL에서 제목에 표시되는 요청 동작과 일치하도록 사용해야 합니다.
WINHTTP_OPTION_SECURE_PROTOCOLS
WinHttpOpen
으로 새 세션 핸들을 만든 후에는 WinHttpSetOption을 WINHTTP_OPTION_SECURE_PROTOCOLS
옵션과 함께 호출하고 호출을 통해 검색한 대응하는 XNetworkingSecurityInformation::enabledHttpSecurityProtocolFlags
를 이 세션 핸들을 사용할, 일치하는 URL의 XNetworkingQuerySecurityInformationForUrlUtf16Async에 전달해야 합니다.
TLS/SSL 핸드셰이크 단계를 확인하는 에서 사용할 수 있도록 XNetworkingSecurityInformation구조를 콘텐츠 개체에 저장해야 합니다.
세션 핸들 캐싱
WinHttpOpen
을 통해 생성한 HTTP 세션 핸들은 메모리 관련 비용이 많이 들며, 시동 비용이 비싸 최초 HTTP 요청이 지연됩니다. 이러한 비용을 방지하려면 타이틀에서 HTTP 세션 핸들을 최대한 많이 캐시하는 것이 좋습니다.
하지만 세션 핸들에서는 WINHTTP_OPTION_SECURE_PROTOCOLS
옵션을 변경할 수 없습니다. WinHTTP 세션 핸들에 매핑한 XNetworkingSecurityInformation::enabledHttpSecurityProtocolFlags
값의 캐시를 유지하여, 각 보안 프로토콜 플래그에 다른 세션 핸들이 있게 해야 합니다.
타이틀이 유지하는 캐시는 일시 중단 알림 시 정리하고, 재개 시에는 (네트워크가 초기화될 때까지 기다린 다음) 처음부터 다시 작성해야 합니다.
WinHttpConnect 고려 사항
세션 핸들과 달리, WinHttpConnect를 통해 생성한 연결 핸들은 캐시해선 안 됩니다. 새 요청 및/또는 재시도를 할 때마다 새 핸들을 만들어야 합니다. 이름에도 불구하고 WinHTTP 연결 핸들은 TCP(서버 전송 제어 프로토콜) 연결과 관계가 없습니다. WinHTTP는 세션 핸들을 이용해 기본 서버 연결의 수명을 관리하며, 새 연결 핸들에 사용할 수 있다면 열린 서버 연결을 자동으로 재사용합니다.
URL 정식화
WinHTTP는 모든 URL을 a~z, A~Z 및 0~9 US-ASCII 문자로 정식화한다고 예상합니다. 정식화에 대한 자세한 내용은 WinHTTP에서의 URL(Uniform Resource Locator)을 참조하세요. 가능하면 타이틀에서 사용하는 URL을 표준 형식으로 하드 코딩하는 것이 좋습니다. 이렇게 하면 WinHttpCrackUrl 및 WinHttpCreateUrl 기능을 사용하여 URL을 동적으로 표준화하는 데 발생하는 메모리 할당 및 성능 문제가 방지됩니다.
URL 분할
WinHTTP에서는 null로 끝나는 호스트 이름 문자열을 WinHttpConnect
로 전달하고, 경로와 개체는 WinHttpOpenRequest
로 전달해야 합니다. 즉 타이틀은 연결된 호스트 이름을 포함하는 전체 URL과 경로 모두를 특정 위치에 전달하고, 다른 곳에는 호스트 이름이나 경로만 전달해야 합니다. 되도록 타이틀에서 두 항목을 모두 하드 코딩해, WinHttpCrackUrl 및 WinHttpCreateUrl을 사용하여 URL을 동적으로 연결하거나 분할하지 않는 것이 좋습니다.
WinHttpOpenRequest 고려 사항
WinHTTP 연결 핸들처럼, WinHttpOpenRequest 함수를 통해 생성한 WinHTTP 요청 핸들은 캐시해선 안 됩니다. 새 요청 및/또는 재시도를 할 때마다 새 핸들을 만들어야 합니다.
타이틀은 항상 WinHttpOpenRequest
을 호출할 때 dwFlags
매개 변수에 대한 WINHTTP_FLAG_SECURE
플래그를 전달하는 것이 좋습니다.
Xbox 토큰 검색 및 적용
Microsoft Game GDK(게임 개발 키트) 타이틀에는 토큰이 자동으로 삽입되지 않습니다. 대신 타이틀은 Microsoft GDK(게임 개발 키트) XUser API로 Xbox 서비스 인증 토큰과 서명을 검색해야 합니다. 타이틀이 사용자를 확보하면 타이틀은 XUserGetTokenAndSignatureUtf16Async를 호출하여 각 요청에 대한 토큰과 서명 문자열을 검색해야 합니다. 그런 다음 이러한 두 문자열을 헤더로 WinHttpAddRequestHeadersEx
, WinHttpSendRequest 또는 WinHttpAddRequestHeaders 호출에 전달해야 합니다.
올바른 서명을 생성하려면 XUserGetTokenAndSignatureUtf16Async에서 타이틀이 모든 머리글 및 전체 본문을 지나도록 예상 합니다. 큰 POST
또는 PUT
있는 경우 제목은 파트너 센터에 구성된 본문의 하위 집합을 전달할 수 있습니다. 자세한 내용은 웹 서비스(NDA 항목)권한 부여 필요를 참조하세요. 현재, Xbox 네트워크는 이 구성을 검색하는 메커니즘을 제공하지 않습니다. 클라이언트는 값을 하드 코딩하거나 맞춤형 타이틀별 끝점을 통해 검색할 것입니다.
XUserGetTokenAndSignatureUtf16Async 내부적으로 필요한 모든 캐싱을 수행하며, 재시도를 포함하여 각 HTTP 시도에 대해 호출 해야합니다. 타이틀이 HTTP 요청에 대한 401 무단 HTTP 응답 상태 코드를 받으면, 타이틀은 요청을 다시 시도하고 Xbox 서비스 인증 토큰을 새로 고치도록 해야 합니다. XUserGetTokenAndSignatureUtf16Async에서 새 토큰을 불러오고 XUserGetTokenAndSignatureOptions:: ForceRefresh 열거형 값을 지나면 이 작업이 수행될 수 있습니다.
XUserGetTokenAndSignatureUtf16Async 호출로 불러들인 XUserGetTokenAndSignatureUtf16Data이(가) 있으면 타이틀은 XUserGetTokenAndSignatureUtf16Data::Token
및 XUserGetTokenAndSignatureUtf16Data::Signature
를 HTTP 머리글로 변경하여 WinHTTP로 지나가야 합니다. 새로운 WinHTTP API WinHttpAddRequestHeadersEx
은(는) Microsoft GDK(게임 개발 키트) 타이틀에서 복잡성을 줄이기 위해 특별히 추가되었습니다. 다음은 이 새 API를 사용하는 방법 예시입니다. 이 새 API는 Xbox One 본체에서 사용할 수 있으며 향후 Windows OS 업데이트를 통해 Windows PC에서도 지원될 예정입니다. 콘솔에서는 추가 할당 및 문자열 형식 변경을 방지하려면 WinHttpAddRequestHeadersEx
을(를) 사용하는 것이 좋습니다.
HRESULT
AddTokenAndSignatureDataToHttpRequest(
XUserGetTokenAndSignatureUtf16Data* userTokenAndSignatureData,
HINTERNET requestHandle
)
{
WINHTTP_EXTENDED_HEADER winhttpHeader[2];
winhttpHeader[0].pwszName = L"Authorization";
winhttpHeader[0].pwszValue = userTokenAndSignatureData->token;
winhttpHeader[1].pwszName = L"Signature";
winhttpHeader[1].pwszValue = userTokenAndSignatureData->signature;
return HRESULT_FROM_WIN32(WinHttpAddRequestHeadersEx(
m_handshakeRequest,
WINHTTP_ADDREQ_FLAG_ADD,
WINHTTP_EXTENDED_HEADER_FLAG_UNICODE,
0,
tokenAndSignature->signatureCount ? 2 : 1,
winhttpHeader));
}
참고 항목
장치나 로그인한 계정이 자신에게 설정된 샌드박스에 액세스할 수 있어야 합니다. 그렇지 않으면 XUserGetTokenAndSignatureUtf16Data
이(가) 실패합니다.
Xbox NSAL(네트워크 보안 인증 목록) 사용
Xbox 네트워크는 NSAL을 사용하여 클라이언트가 웹 서비스에 대한 보안과 인증된 연결을 설정하도록 합니다. 타이틀은 파트너 센터에서 구성 과정의 일부로 NSAL의 내용을 관리합니다. 자세한 내용은 파트너 센터에서 웹 서비스 설정(NDA 항목)권한 부여 필요을 참조하세요. 그런 다음 각 타이틀에 대한 NSAL 구성을 자동으로 다운로드하고, 둘 모두를 사용하여 적절한 Xbox 서비스 토큰을 생성하며, 각 타이틀의 끝점을 위한 인증서를 고정합니다.
WinHTTP 비동기 상태 머신 고려 사항
WinHTTP 비동기 상태 머신은 Windows 데스크톱과 콘솔 버전이 동일합니다.
WinHttpSetStatusCallback 함수를 사용하여 콜백 함수를 하나 이상의 알림과 함께 등록합니다. WinHTTP는 자산이 하는 일을 자세하고 투명하게 보여주기 때문에, 디버깅 목적의 dwNotificationFlags
매개 변수에는 WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS
플래그 사용을 권장합니다. 대부분의 알림은 사용자의 작업을 요구하지 않지만, 데이터를 로깅하면 문제의 근본 원인을 해결하는 데 도움이 됩니다.
WinHTTP는 알림에 단일 스레드를 사용합니다. 타이틀에서 알림 기능을 최대한 차단하지 않아야 합니다. 차단하면 프로세스 내의 모든 HTTP 요청이 진행되지 않습니다. 처리되지 않은 알림은 커널 모드 메모리를 늘려 크래시를 유발할 수도 있습니다.
WinHTTP는 보내기 또는 받기 버퍼를 복사하지 않으며, 해당하는 완료 콜백 시까지 해당 버퍼를 할당된 상태로 유지해야 합니다.
WinHttpSendRequest를 호출할 때는 대응하는 WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE
알림을 받을 때까지 보내기 버퍼를 계속 할당하고 유효한 상태로 유지해야 합니다. 마찬가지로, WinHttpReadData를 호출할 때는 대응하는 WINHTTP_CALLBACK_STATUS_READ_COMPLETE
알림을 받을 때까지 받기 버퍼를 계속 할당하고 유효한 상태로 유지해야 합니다. 크기가 8KB 이상인 받기 버퍼를 사용하여 스택 고갈을 유발할 수 있는 재귀 문제도 방지하는 것이 좋습니다.
또한 타이틀에서 비동기 WinHttpQueryDataAvailable
/WinHttpReadData
주기를 계속 진행하고 항상 WinHTTP 콜백 차단을 방지하여 WinHTTP 버퍼가 제대로 비워지도록 해야 합니다.
TLS(전송 계층 보안)/SSL(Secure Sockets Layer) 핸드케이크 유효성 검사
타이틀은 TLS/SSL 핸드셰이크에 추가적인 유효성 검사를 수행하고 TLS 1.2만 사용하는 것이 좋습니다.
WINHTTP_CALLBACK_STATUS_SENDING_REQUEST
알림 내에서 추가 유효성 검사를 수행합니다. 알림 내에서 XNetworkingVerifyServerCertificate 기능을 호출해야 하며 지난 해당 XNetworkingQuerySecurityInformationForUrlUtf16Async 호출에서 불러온XNetworkingSecurityInformation 구조에서 지나야 합니다. 인증서 체인이 잘못된 경우 이 함수는 실패합니다. 콜백이 완료되기 전에 WinHTTP 핸들을 즉시 닫아 손상된 서버에서/서버로 데이터가 전송되지 않도록해야합니다.
콘솔의 Fiddler 기능을 위해서는 인증서 체인 뿐만 아니라 XNetworkingVerifyServerCertificate 함수가 필요 합니다.
WinHTTP 디버깅
Fiddler는 WinHTTP 트래픽을 확인하고 디버깅하는 유용한 도구입니다. Fiddler가 타이틀 트래픽을 캡처하려면, WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY
, WINHTTP_NO_PROXY_NAME
및 WINHTTP_NO_PROXY_BYPASS
플래그를 WinHttpOpen
에 전달해야 합니다.
WINHTTP_CALLBACK_STATUS_SENDING_REQUEST
알림 콜백 내에서 XNetworkingVerifyServerCertificate도 호출 해야 합니다.
참고 항목
HTTP 모니터는 Microsoft GDK(게임 개발 키트) 타이틀에서 작동하지 않습니다.