블로킹 vs 논블로킹 소켓

Jaemyeong Lee·2025년 1월 14일

게임 서버1

목록 보기
130/220

블로킹 소켓의 의미와 장단점

블로킹 동작

  • 블로킹 소켓에서 accept, recv, send는 준비될 때까지 호출 스레드를 멈춥니다.
  • 코드가 직관적이라 입문/단일 연결 테스트에는 이해하기 쉽습니다.

왜 서버에서 문제가 되는가

상황결과
단일 스레드가 recv에서 대기다른 클라이언트 처리 지연
느린 클라이언트/유휴 연결 증가처리량 급감
동접 증가스레드 고갈 또는 대기 시간 폭증

게임 서버 관점

  • MMO/FPS 서버는 "누가 언제 보낼지 모르는" 이벤트 기반 트래픽입니다.
  • 블로킹 기반 단순 루프는 동접이 커질수록 구조적으로 불리합니다.

논블로킹 소켓으로 전환

설정

u_long on = 1;
ioctlsocket(sock, FIONBIO, &on);  // 1: non-blocking, 0: blocking

동작 변화

함수블로킹 소켓논블로킹 소켓
accept접속 올 때까지 대기즉시 반환
recv데이터 올 때까지 대기즉시 반환
send버퍼 여유 생길 때까지 대기 가능즉시 반환(준비 안 되면 실패 코드)

핵심 변화

  • "대기"가 "즉시 상태 확인"으로 바뀝니다.
  • 대신 호출 결과를 더 세밀하게 분기 처리해야 합니다.

WSAEWOULDBLOCK 정확히 이해하기

의미

  • 논블로킹 모드에서 준비되지 않은 I/O를 호출했을 때 나오는 상태 코드입니다.
  • "진짜 장애"가 아니라 "지금은 아직 안 됨, 나중에 다시 시도"에 가깝습니다.

예시 분기

int n = recv(s, buf, sizeof(buf), 0);
if (n > 0) {
    // 데이터 처리
} else if (n == 0) {
    // 연결 종료
} else {
    int err = WSAGetLastError();
    if (err == WSAEWOULDBLOCK) {
        // 아직 데이터 없음: 다음 I/O 사이클에서 재시도
    } else {
        // 실제 오류 처리
    }
}

관련 코드 주의

  • accept, recv, send, non-blocking connect 모두 유사 패턴이 필요합니다.
  • 상태 코드와 실제 에러 코드를 섞어 처리하면 장애 원인 추적이 어려워집니다.

논블로킹만으로는 부족한 이유

Busy Polling 문제

  • 논블로킹 소켓을 while(true)로 계속 확인하면 CPU를 과도하게 소모합니다.
  • 연결 수가 많을수록 "아무 일도 없는데 돌기만 하는" 루프 비용이 커집니다.

해결 방향

단계아이디어
1논블로킹으로 대기 블로킹 제거
2준비된 소켓만 깨워주는 I/O multiplexing 도입
3대규모 동접에서는 IOCP 같은 완료 기반 모델 사용

다음 Part와 연결

  • select, WSAEventSelect, Overlapped, IOCP는 모두 "불필요한 폴링을 줄이기 위한 진화"입니다.

블로킹/논블로킹 선택 가이드

환경권장
단일 연결 디버깅/학습블로킹도 충분
소수 연결 툴/테스트블로킹 + 스레드 분리 가능
동접이 큰 게임 서버논블로킹 + I/O 모델 필수

실무 원칙

  • "논블로킹으로 바꿨다"가 끝이 아니라, 이벤트/완료 기반 구조까지 같이 설계해야 합니다.
  • 상태 코드를 정상 흐름으로 처리하는 코드 스타일(분기 표준화)이 중요합니다.

강의 시 유의사항

강조 포인트

  • 블로킹은 나쁜 기술이 아니라 "적용 범위가 제한된 기술"임을 설명하세요.
  • WSAEWOULDBLOCK을 에러가 아닌 "미준비 상태"로 분명히 구분시키세요.
  • 논블로킹의 목적은 속도보다 확장성/응답성 확보입니다.

자주 하는 오해

오해바로잡기
논블로킹이면 자동으로 고성능폴링 구조면 CPU만 더 쓸 수 있음
WSAEWOULDBLOCK은 장애 코드논블로킹에서는 정상적인 상태 코드
블로킹은 절대 사용하면 안 됨디버깅/소규모/단순 시나리오에선 유용

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

  • 블로킹에서 논블로킹으로 바꿨을 때 코드 구조가 어떻게 달라지는가?
  • recv에서 SOCKET_ERROR가 나왔을 때 어떤 순서로 분기해야 하는가?
  • 왜 논블로킹 다음 단계로 I/O 모델이 필수적으로 등장하는가?

profile
李家네_공부방

0개의 댓글