필수 헤더 및 라이브러리

#define WIN32_LEAN_AND_MEAN
#include <WinSock2.h>   // Windows.h보다 먼저
#include <WS2tcpip.h>
#include <Windows.h>    // 필요할 때만

#pragma comment(lib, "ws2_32.lib")
  • 핵심은 WinSock2.h를 먼저 포함하는 것입니다.
  • ws2_32.lib 링크가 빠지면 컴파일은 되더라도 링크 단계에서 실패합니다.

헤더 순서가 왜 중요한가

순서결과
WinSock2.h -> Windows.h정상
Windows.h -> WinSock2.hWinsock 선언 충돌/이상한 에러 가능
  • Windows.h가 오래된 winsock.h 경로를 끌고 들어와 충돌이 날 수 있습니다.
  • 입문 단계에서 가장 많이 헤매는 포인트이므로 반드시 규칙으로 고정하세요.

프로젝트 설정 체크

항목체크 포인트
플랫폼x64/x86 통일
구성Debug/Release 혼용 금지
링크ws2_32.lib 누락 여부 확인
PCH공통 include 순서를 프로젝트 전역에서 고정

WSAStartup 정확히 이해하기

기본 초기화 패턴

WSADATA wsaData{};
int ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (ret != 0) {
    // 주의: WSAStartup 실패는 ret 자체가 에러 코드
    return false;
}
  • WSAStartup은 "Winsock 런타임 사용 선언"입니다.
  • 성공 전에는 소켓 API를 정상 사용하면 안 됩니다.

버전 협상 확인

if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
    WSACleanup();
    return false;
}
항목의미
MAKEWORD(2,2)앱이 원하는 Winsock 2.2 버전 요청
wVersion실제로 사용할 버전(협상 결과)
wHighVersion시스템이 지원하는 최고 버전
  • 요청과 결과가 다를 수 있으므로 wVersion 검사를 습관화하면 안전합니다.

WSACleanup 대칭 호출

WSACleanup();
  • WSAStartup 성공 호출 수만큼 WSACleanup이 필요합니다.
  • 라이브러리/모듈이 제각각 cleanup을 호출하면 조기 종료 버그가 날 수 있으니 수명 주기를 중앙에서 관리하세요.

초기화 수명 관리 패턴

권장 수명 주기

  1. 프로세스 시작 시 1회 초기화
  2. 네트워크 리소스 생성/사용
  3. 종료 시 소켓 정리 후 cleanup

RAII 가드 예시

class WinsockGuard {
public:
    WinsockGuard() {
        WSADATA data{};
        int ret = WSAStartup(MAKEWORD(2, 2), &data);
        ok_ = (ret == 0);
    }
    ~WinsockGuard() {
        if (ok_) WSACleanup();
    }
    bool Ok() const { return ok_; }
private:
    bool ok_ = false;
};
  • 초기화/정리를 객체 수명과 묶으면 누락 실수를 크게 줄일 수 있습니다.

서버 프로젝트 실무 팁

  • 앱 진입점(main)에서 Winsock 수명을 통제하는 구조가 가장 안정적입니다.
  • 하위 모듈이 임의로 cleanup하지 않도록 책임 경계를 명확히 하세요.

에러 확인과 진단

일반 소켓 API 실패 처리

SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET) {
    int err = WSAGetLastError();
    // 함수명 + err + 문맥 로그
}

int sent = send(s, buf, len, 0);
if (sent == SOCKET_ERROR) {
    int err = WSAGetLastError();
}
  • 대부분의 Winsock 함수는 실패 시 WSAGetLastError()로 원인을 조회합니다.

WSAStartup는 예외 규칙

  • WSAStartup 실패는 WSAGetLastError()보다 반환값(ret) 자체를 우선 사용합니다.
  • 대표 실패 코드: WSASYSNOTREADY, WSAVERNOTSUPPORTED, WSAEPROCLIM, WSAEFAULT

로그 표준화

로그 항목예시
함수명connect
에러 코드10061
문맥127.0.0.1:7777
재시도 여부retry=false
  • 에러 번호만 남기지 말고, 호출 문맥(주소/포트/상태)을 함께 기록해야 재현이 쉬워집니다.

입문 단계에서 자주 하는 실수

실수결과예방
헤더 순서 오류컴파일/링크 이상 현상include 순서 규칙 고정
WSAStartup 누락모든 소켓 API 실패초기화 가드 도입
WSACleanup 누락리소스 정리 누락수명 주기 대칭 관리
cleanup 조기 호출이후 소켓 호출 불안정main에서 중앙 통제
에러 로그 부실원인 추적 어려움함수명+코드+문맥 필수

강의 시 유의사항

강조 포인트

  • Part 2의 핵심은 "코드 한 줄"이 아니라 초기화 수명 관리 규칙입니다.
  • WSAStartup 반환값 해석과 일반 Winsock 함수의 에러 처리 방식을 구분해서 설명하세요.
  • include 순서 규칙은 암기가 아니라 "충돌 예방 규약"으로 가르치세요.

시연 추천

  • Windows.h를 먼저 include했을 때의 실패 사례 1회 시연
  • WSAStartup을 주석 처리했을 때 socket이 어떻게 실패하는지 확인
  • 로그 형식(함수명/코드/문맥) 템플릿을 실제로 출력

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

  • WinSock2.hWindows.h보다 먼저 include해야 하는가?
  • WSAStartup 실패 시 어떤 값을 먼저 확인해야 하는가?
  • WSAStartup/WSACleanup의 호출 수명 주기를 팀 규칙으로 어떻게 잡을 것인가?

profile
李家네_공부방

0개의 댓글