소켓 유틸리티

Jaemyeong Lee·2025년 1월 15일

게임 서버1

목록 보기
132/220

왜 SocketUtils가 필요한가

단순 편의 이상의 역할

  • 소켓 API 호출을 한 곳에 모아 에러 처리 규칙을 일관화합니다.
  • 옵션 설정/바인딩/리스닝 순서를 표준화해 휴먼 에러를 줄입니다.
  • 플랫폼 의존 코드(Winsock 확장 함수 로딩)를 캡슐화해 상위 로직을 단순화합니다.

팀 개발 관점 이점

이점설명
일관성함수별 반환/로그 포맷 통일
유지보수성정책 변경 시 유틸리티 한 곳만 수정
테스트성실패 경로를 모의(mock)하기 쉬움

SocketUtils 설계 원칙

API 설계

  • "true/false 반환 + 내부 에러 로그" 또는 "에러 코드 반환" 중 하나로 통일
  • 성공/실패 기준을 명확히(예: SOCKET_ERROR, INVALID_SOCKET)
  • 호출 순서가 중요한 작업은 조합 함수로 제공

권장 래퍼 예시

SocketUtils::Init();                     // WSAStartup + 확장 함수 로드
SocketUtils::SetReuseAddress(listenSock, true);
SocketUtils::BindAnyAddress(listenSock, 7777);
SocketUtils::Listen(listenSock, SOMAXCONN);
SocketUtils::Close(listenSock);
SocketUtils::Clear();                    // WSACleanup

로그 표준화

  • 최소 항목: 함수명, 소켓 핸들, 에러 코드, 주소/포트 문맥
  • 네트워크 코드에서 "어디서 실패했는지"가 바로 보이도록 메시지를 고정 형식으로 남깁니다.

Winsock 확장 함수 개요

대상 함수

함수용도
AcceptEx비동기 accept + (옵션) 초기 데이터 수신
ConnectEx비동기 connect
DisconnectEx비동기 disconnect / 소켓 재사용 지원

중요한 특징

  • 표준 헤더 선언만으로 바로 호출되지 않습니다.
  • 런타임에 함수 포인터를 가져와야 합니다.
  • 주로 Overlapped/IOCP 모델에서 핵심 역할을 합니다.

함수 포인터 로딩 패턴 (WSAIoctl)

AcceptEx 로딩 예시

LPFN_ACCEPTEX gAcceptEx = nullptr;
GUID guidAcceptEx = WSAID_ACCEPTEX;
DWORD bytes = 0;

int ret = WSAIoctl(listenSock,
                   SIO_GET_EXTENSION_FUNCTION_POINTER,
                   &guidAcceptEx, sizeof(guidAcceptEx),
                   &gAcceptEx, sizeof(gAcceptEx),
                   &bytes, nullptr, nullptr);
if (ret == SOCKET_ERROR) {
    int err = WSAGetLastError();
    // 로딩 실패 처리
}

실무 규칙

  • 보통 SocketUtils::Init()에서 한 번 로드하고 전역/싱글톤으로 보관합니다.
  • 로딩 실패 시 서버 시작을 중단하는 정책이 일반적입니다.
  • 확장 함수는 "옵션 기능"이 아니라 IOCP 경로의 핵심 의존성입니다.

함수별 필수 주의사항

AcceptEx

  • listen 소켓과 별도로 "미리 생성한 accept 소켓"이 필요합니다.
  • 완료 후 setsockopt(..., SO_UPDATE_ACCEPT_CONTEXT, ...) 업데이트가 필요할 수 있습니다.

ConnectEx

  • 대상 소켓은 ConnectEx 전에 로컬 주소로 bind되어 있어야 합니다(Windows에서 자주 놓침).
  • 완료 후 SO_UPDATE_CONNECT_CONTEXT를 적용해야 일부 소켓 API 동작이 정상화됩니다.

DisconnectEx

  • TF_REUSE_SOCKET 플래그를 사용하면 소켓 재사용 시나리오에 유리합니다.
  • 재사용 정책을 잘못 쓰면 세션 수명 관리가 꼬일 수 있으니 명확한 규약이 필요합니다.

IOCP 준비 관점에서의 위치

왜 Part 13에서 미리 다루나

  • Part 18(IOCP)에서 갑자기 등장하면 난도가 급상승합니다.
  • 지금 단계에서 "함수 포인터를 미리 로드한다"는 개념을 잡아두면 이후 학습이 훨씬 쉬워집니다.

연결 흐름

  1. Part 13: 유틸리티 + 확장 함수 준비
  2. Part 16~17: 동기/비동기/Overlapped 이해
  3. Part 18: IOCP에서 실제 운용

강의 시 유의사항

강조 포인트

  • SocketUtils의 목적은 "코드 짧게 쓰기"보다 실수 방지와 정책 일관화입니다.
  • 확장 함수는 "고급 기능"이 아니라 Windows 고성능 서버의 기본 재료입니다.
  • 로딩 실패를 무시하면 이후 IOCP 단계에서 난해한 장애로 나타날 수 있습니다.

자주 하는 오해

오해바로잡기
유틸리티는 없어도 큰 차이 없다규모가 커질수록 에러 일관성/유지보수성 격차가 커짐
ConnectEx는 connect의 완전 대체사전 bind, 완료 후 context 업데이트 등 추가 규칙 필요
확장 함수는 링크하면 자동 사용 가능WSAIoctl로 런타임 함수 포인터 획득이 필요

체크 질문 (스스로 답해보기)

  • SocketUtils가 없을 때 팀 코드에서 가장 먼저 깨지는 품질 요소는 무엇인가?
  • ConnectEx 전에 bind가 필요한가?
  • 확장 함수 로딩 실패를 서버 시작 단계에서 차단해야 하는 이유는?

profile
李家네_공부방

0개의 댓글