Microsoft 게임 개발 키트의 Windows 소켓 소개
Microsoft 게임 개발 키트(GDK)는 Windows 소켓 2(Winsock) API 사용을 지원합니다.
Winsock(Windows Sockets 2)을 활용하면 사용 중인 네트워크 프로토콜과 관계없이 네트워크를 통해 애플리케이션 데이터를 전송하는 고급 인터넷, 인트라넷 및 기타 네트워크 지원 애플리케이션을 만들 수 있습니다.
Microsoft GDK(게임 개발 키트) 타이틀이 Winsock과 상호 작용하는 방식은 일반적으로 Win32 프로그램이 Winsock과 상호 작용하는 방식과 동일합니다.
이 항목에서는 Microsoft GDK(게임 개발 키트) 타이틀에서 Winsock 사용과 관련된 사소한 차이점과 모범 사례에 대해 설명합니다.
설정
이 섹션에서는 Winsock API를 사용할 때 포함해야 하는 .h 및 .lib 파일에 관해 설명합니다.
- 소스 파일에
#include <winhttp.h>
을(를) 추가합니다. - PC 타이틀의 경우
Winhttp.lib
에 대해 계속 연결합니다. - Xbox 본체 타이틀의 경우
Winhttp.lib
대신XGamePlatform.lib
에 연결해야 합니다.
WINAPI_PARTITION_GAMES
API 제품군의 API만 Microsoft GDK(게임 개발 키트) 타이틀에서 작동합니다.
네트워크 초기화
WSAStartup을 처음 호출하기 전에 Microsoft GDK(Game Development Kit) 타이틀은 네트워킹 스택이 준비되었는지 확인해야 합니다.
WSAStartup
이(가) 타이틀 시작 과정에서 너무 일찍 호출되면 WSAStartup
또는 후속 Winsock 호출이 실패할 수 있습니다. 네트워킹 스택이 준비된 시기를 파악하는 방법에 대한 자세한 내용은 네트워크 초기화 및 연결을 참조하세요.
일시 중단 및 재개
RegisterAppStateChangeNotification
을(를) 통해 일시 중단 및 다시 시작 이벤트를 등록해야 합니다. 일시 중단 시 모든 소장 핸들을 닫고 WSACleanup을 호출해야 합니다. 재개할 때 WSAStartup을 호출하고 새 소켓을 만들기 전에 네트워크 초기화를 다시 기다려야 합니다.
Microsoft 게임 개발 키트(GDK) 기본 로컬 UDP(사용자 데이터그램 프로토콜) 멀티플레이어 포트 API
Microsoft GDK(게임 개발 키트) 기본 로컬 UDP 멀티플레이어 포트 API는 UDP를 통한 게임 내 통신을 용이하게 하기 위해 Winsock을 사용하여 타이틀이 바인드해야 하는 최적의 동적으로 선택된 포트를 반환합니다. Microsoft GDK(게임 개발 키트) 플랫폼은 이 특정 포트가 각 사용자의 특정 네트워킹 환경에서 가장 잘 작동하도록 합니다. 이 특정 포트를 사용하면 플랫폼의 고객 지원 및 진단 흐름의 사용을 극대화하고, 표준화된 NAT(네트워크 주소 변환) 호환성을 높이고, 표준화된 UPnP™(범용 플러그 앤 플레이) 인증 장치 기능을 제공하고, QoS(서비스 품질) 라우터 및 ISP 알고리즘을 위해 실시간에 민감한 패킷을 식별합니다.
UDP 포트는 P2P 네트워크 토폴로지에 의존하는 타이틀과 특히 관련이 있습니다. 이 포트는 방화벽 펀칭을 수행하지 않고 인바운드 UDP 패킷이 방화벽을 통과하도록 허용하는 유일한 포트입니다. Microsoft GDK(게임 개발 키트)의 P2P 네트워크 토폴로지에 의존하는 타이틀은 여전히 중간 또는 엄격한 NAT 유형을 가진 클라이언트를 위한 NAT 펀칭 솔루션과 함께 자체 공용 IP 주소 및 포트 검색을 제공해야 합니다. 기본 포트 자체는 이러한 기술의 성공률을 개선하지만 이들을 대체하는 것은 아닙니다.
클라이언트-서버 네트워크 토폴로지를 사용하는 타이틀에도 UDP 포트를 사용하는 이점이 있습니다. 문제 해결, 범용 플러그 앤 플레이™ 및 패킷 식별은 병원, 호텔 및 대학 기숙사에서 일반적으로 사용되는 종속 포털 및 기타 원본 기반 필터링 접근 방식과 여전히 관련이 있습니다.
Microsoft GDK(게임 개발 키트) 타이틀은 기본 멀티플레이어 및 채팅 네트워크 트래픽에 기본 로컬 UDP 멀티플레이어 포트를 사용하는 것이 좋습니다.
소켓 보안
Microsoft GDK(게임 개발 키트) 타이틀은 Winsock API를 사용하여 네트워크를 통해 전송되는 모든 데이터에 대해 적절한 보안 및 암호화가 있는지 확인하는 역할을 합니다.
BCrypt, WinCrypt, schannel, 및 기타 표준 Windows API가 권장 암호화 기본 형식을 제공합니다. Microsoft GDK(게임 개발 키트) 타이틀은 이러한 API를 사용하여 모든 소켓 흐름에 대해 DTLS(데이터그램 전송 계층 보안) 및 기타 표준화된 보안 프로토콜을 구현해야 합니다.
자체 보안 모델을 구현하지 않으려는 타이틀의 경우 Microsoft GDK(게임 개발 키트) 라이브러리 PlayFab Party는 무엇보다도 완벽하고 통합된 소켓 보안 스토리를 제공합니다.
소켓 메모리 고려 사항
Microsoft GDK(게임 개발 키트) 타이틀은 현재 모든 WinSock 및 WinHTTP 사용을 위해 네트워크 스택에 약 16MB만 사용할 수 있으며, 그 이후에는 시스템이 불안정해질 수 있습니다. 가장 큰 메모리 소비 소스 중 하나는 WinSock 커널 모드 송신 및 수신 메모리 풀로, 수신 패킷은 많은 recv
개 변종 중 하나를 통해 유선 또는 타이틀의 사용자 모드 메모리로 전송될 수 있을 때까지 저장됩니다.
특히 고대역폭 상황의 경우, 최소한 원격 피어 또는 서버가 푸시하는 속도와 동일한 속도로 낮은 대기 시간으로 데이터를 자체 사용자 모드 버퍼로 전송할 책임이 있습니다. 복잡성과 보장을 늘려 이를 수행하는 몇 가지 방법이 있지만, 아래 모든 제안의 기본 목표는 데이터가 도착하는 즉시 사용자 모드 버퍼를 항상 보류하여 커널이 증가하는 메모리를 할당할 필요가 없도록 하는 것입니다. 순효과는 처리되지 않은 보류 중인 데이터의 메모리 사용량을 극도로 제한된 커널 풀에서 훨씬 큰 타이틀 메모리 풀 내에서 사용자가 직접 관리하는 메모리로 변경하는 것입니다.
WinSock을 사용하는 상위 수준의 API는 일반적으로 소켓의 커널 메모리 사용을 제어하는 메커니즘을 가지고 있습니다. WinHTTP 및 XCurl은(는) 각각의 읽기 알림 메커니즘을 통해 커널 메모리 사용량을 제어할 수 있도록 하는 반면, XSAPI 및 PlayFabParty와 같은 다른 API는 아래 기술로 커널 메모리 사용량을 최소화합니다.
Berkley(BSD) 소켓
Berkley 소켓 API를 계속 차단하고 싶다면, recv 호출의 빈도를 늘려야 합니다. 다른 곳에서 처리하기 위해 수신된 데이터를 큐에 넣는 타이트한 루프가 있는 전용 스레드를 사용하는 것이 좋습니다. 이상적으로는 스레드가 항상 recv 호출 내에서 차단됩니다. recv 호출 밖에서 보내는 시간은 커널 메모리 사용량이 다시 recv 호출을 기다리는 시간이 될 수 있습니다. recv를 다시 호출하기 전에 데이터를 처리하려고 하면 타이틀이 뒤로 밀리고, 데이터가 계속 고속으로 수신되는 한 커널 메모리 사용량이 증가할 수 있습니다. 또한 커널 버퍼 크기 경계에 맞추고 지터 및 버스트 전송 패턴을 지원하기 위해 최소 8k의 버퍼 크기를 지정할 것을 권고한다.
WinSock 중첩 I/O
WinSock의 중첩된 I/O를 사용하면 사용자 모드 수신 버퍼를 비동기적으로 보류 상태로 유지할 수 있습니다. 또한 커널이 메모리 버퍼를 직접 사용할 수 있도록 허용하고 추가 메모리 복사를 피할 수 있습니다(Berkley 소켓 패러다임과는 달리). 버퍼가 항상 보류된다고 가정하면 커널은 수신된 데이터에 대해 전혀 할당되지 않습니다. 또한 중복된 I/O를 사용하면 SO_RCVBUF와 SO_SNDBUF를 특수값 0으로 설정할 수 있으며, 이는 커널 메모리가 할당되는 것을 대부분 방지할 수 있습니다.
이 방법은 거의 모든 시나리오에서 소켓에서 사용하는 메모리를 관리하는 가장 좋은 방법입니다.
등록된 I/O
등록된 I/O는 가장 낮은 지연 시간을 제공하고 송신 및 수신 작업에 사용되는 커널 메모리가 없음을 보장하는 복잡한 네트워킹 API입니다. 커널에서 직접 사용하는 여러 수신/발송 버퍼를 설정하여 수신 데이터를 위한 버퍼가 항상 준비되어 있는지 확인할 수 있습니다.
최대 UDP 전송 단위 크기
이론적인 최대 페이로드 크기가 Microsoft GDK(게임 개발 키트)에 존재하지만, 실제로 특정 연결의 최대값은 네트워크 연결 유형에 따라 달라집니다. 타이틀이 실행되는 동안 변동할 수도 있습니다. 타이틀이 실행되는 동안 실제 MTU(최대 전송 장치)를 파악하고 MTU의 변동에 반응하려고 시도하는 대신, 1,384바이트의 최대 UDP 페이로드가 되도록 네트워킹 코드를 설계해야 합니다. 이 값은 모든 네트워킹 구성에서 전송 중 조각화를 피하면서 안전하게 사용할 수 있는 값입니다. 소켓 유형이 IPv4이든 IPv6이든 상관없이 이를 권장합니다.
1,384바이트보다 큰 페이로드의 전송은 종종 IP 수준의 패킷 조각화가 필요합니다. IP 패킷 조각화는 ISP 및 사용자 홈 라우터와 장치에서 잘 지원되지 않습니다. 이러한 네트워크 구성에서 IP 패킷 조각화는 Winsock API의 실패를 초래하지는 않습니다. 조각화는 대신 타이틀에 대한 패킷 손실로 나타납니다. IP 수준 패킷 조각화를 방지하려면 패킷 페이로드의 안전한 최대값으로 1,384 바이트를 사용하세요.
타이틀이 조각화를 방지하도록 하고 타이틀에서 최소 멀티 플레이어 네트워크 요건과 관련된 Xbox 요건을 충족하도록 지원하려면, 타이틀이 개방하는 모든 소켓에 소켓 옵션 IP_DONTFRAGMENT
및 IP_USER_MTU
를 적용해야 합니다.
XGameRuntimeIsFeatureAvailable(XGameRuntimeFeature::XNetworking)에서 true
를 반환하는 경우, 이러한 플래그는 Microsoft GDK(게임 개발 키트) 타이틀에만 사용할 수 있습니다.
XNetworking
기능을 사용할 수 없는 경우 setsockopt
호출이 실패합니다. 다음 예제는 이러한 두 소켓 옵션을 설정하는 방법을 보여줍니다.
HRESULT
ApplyFragmentationSocketOptions(
SOCKET s
)
{
int value = 1;
int error = setsockopt(s, IPPROTO_IP, IP_DONTFRAGMENT, (char *)&value, sizeof(value));
if (error == SOCKET_ERROR)
{
return HRESULT_FROM_WIN32(WSAGetLastError());
}
value = 1384;
error = setsockopt(s, IPPROTO_IP, IP_USER_MTU, (char *)&value, sizeof(value));
if (error == SOCKET_ERROR)
{
return HRESULT_FROM_WIN32(WSAGetLastError());
}
return S_OK;
}