필수 헤더 및 라이브러리
기본 include / link 세팅
#define WIN32_LEAN_AND_MEAN
#include <WinSock2.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.h | Winsock 선언 충돌/이상한 에러 가능 |
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) {
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회 초기화
- 네트워크 리소스 생성/사용
- 종료 시 소켓 정리 후 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();
}
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.h를 Windows.h보다 먼저 include해야 하는가?
WSAStartup 실패 시 어떤 값을 먼저 확인해야 하는가?
WSAStartup/WSACleanup의 호출 수명 주기를 팀 규칙으로 어떻게 잡을 것인가?