setsockopt / getsockopt 기본 규칙

기본 형태

int value = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
               reinterpret_cast<const char*>(&value),
               sizeof(value)) == SOCKET_ERROR) {
    int err = WSAGetLastError();
}

int out = 0;
int len = sizeof(out); // Winsock은 int 길이 사용
if (getsockopt(sock, SOL_SOCKET, SO_TYPE,
               reinterpret_cast<char*>(&out), &len) == SOCKET_ERROR) {
    int err = WSAGetLastError();
}

level 의미

Level용도
SOL_SOCKET소켓 공통 옵션
IPPROTO_IPIPv4 레벨 옵션
IPPROTO_TCPTCP 전용 옵션

적용 타이밍

  • 옵션마다 "bind 전에 설정해야 의미 있는지"가 다릅니다.
  • 서버 코드에서는 보통 socket() 직후, bind() 전에 필요한 옵션을 먼저 설정합니다.

주요 옵션 한눈에 보기

옵션목적기본 권장
SO_REUSEADDR포트 재바인딩 유연화개발/테스트 환경에서 자주 사용
SO_EXCLUSIVEADDRUSE (Windows)포트 독점 바인딩운영 서버에서 고려
TCP_NODELAYNagle 비활성화(지연 감소)실시간 게임 트래픽에 대체로 ON
SO_KEEPALIVE장기 유휴 연결 생존 확인보조 수단(앱 heartbeat 우선)
SO_SNDBUF/SO_RCVBUF송수신 버퍼 크기 조정지표 기반 튜닝
SO_LINGERclose 동작 제어명확한 의도 없으면 기본값 유지

SO_REUSEADDR와 Windows 주의점

문제 상황

  • 서버 재시작 직후 bind에서 WSAEADDRINUSE가 발생할 수 있습니다.
  • 원인 중 하나는 이전 연결의 TIME_WAIT 상태입니다.

기본 설정 예시

int opt = 1;
setsockopt(listenSock, SOL_SOCKET, SO_REUSEADDR,
           reinterpret_cast<const char*>(&opt), sizeof(opt));

Windows 실무 주의

  • Windows에서 SO_REUSEADDR 의미는 Unix 계열과 완전히 같지 않습니다.
  • 운영 서버에서는 의도치 않은 중복 바인딩/포트 하이재킹 위험을 줄이기 위해
    SO_EXCLUSIVEADDRUSE를 고려하는 경우가 많습니다.
int opt = 1;
setsockopt(listenSock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
           reinterpret_cast<const char*>(&opt), sizeof(opt));
  • 팀 규약으로 "개발 환경은 REUSEADDR, 운영은 EXCLUSIVEADDRUSE 우선"처럼 명문화하면 혼선을 줄일 수 있습니다.

TCP_NODELAY와 Nagle 트레이드오프

Nagle 알고리즘 요약

  • 작은 패킷을 모아 전송해 패킷 오버헤드를 줄입니다.
  • 대신 즉시 보내지 않아 지연이 증가할 수 있습니다.

게임에서 왜 자주 끄나

  • 실시간 입력/위치 업데이트는 "작고 자주" 발생합니다.
  • Nagle + Delayed ACK 조합에서 체감 지연이 튈 수 있습니다.
  • 그래서 실시간 게임 채널은 TCP_NODELAY ON이 흔합니다.

설정 예시

int opt = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
           reinterpret_cast<const char*>(&opt), sizeof(opt));

오해 금지

  • TCP_NODELAY를 켠다고 무조건 성능이 좋아지진 않습니다.
  • 대량 전송/배치 전송 중심이라면 패킷 수 증가로 오히려 불리할 수 있습니다.

SO_KEEPALIVE와 앱 레벨 heartbeat

역할

  • 장시간 유휴 연결이 끊겼는지 OS 레벨에서 감지하는 보조 기능입니다.

한계

  • 기본 keepalive 간격은 게임 실시간 요구에 비해 매우 길 수 있습니다.
  • 따라서 게임 서버는 보통 앱 레벨 핑/퐁(heartbeat)을 별도로 둡니다.

권장 사용

  • SO_KEEPALIVE는 안전망으로 사용
  • 실제 세션 타임아웃 판정은 앱 heartbeat 기준으로 운영

송수신 버퍼 크기 튜닝

조정 예시

int snd = 256 * 1024;
int rcv = 256 * 1024;
setsockopt(sock, SOL_SOCKET, SO_SNDBUF, reinterpret_cast<const char*>(&snd), sizeof(snd));
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<const char*>(&rcv), sizeof(rcv));

트레이드오프

크게 설정작게 설정
버스트 흡수 유리, drop 감소 가능메모리 절약, 지연 관측이 더 민감
세션 수가 많으면 메모리 급증 가능피크 트래픽에서 막힘 증가 가능

튜닝 원칙

  • 감으로 바꾸지 말고 지표(지연, WOULDBLOCK, 큐 길이)로 판단
  • 부하 테스트 전/후 비교로 회귀 검증

SO_LINGER는 신중하게

의미

  • close/closesocket 시 남은 데이터 처리와 종료 방식을 제어합니다.

주의

  • 잘못 설정하면 종료 시 블로킹, 예기치 않은 RST 전송 등 부작용이 생길 수 있습니다.
  • 명확한 요구가 없다면 기본 동작을 유지하는 편이 안전합니다.

강의 시 유의사항

강조 포인트

  • 소켓 옵션은 "좋은 옵션 모음"이 아니라 트레이드오프 선택 도구입니다.
  • SO_REUSEADDR는 편하지만 Windows 특성을 모르고 쓰면 운영 리스크가 생길 수 있습니다.
  • TCP_NODELAY는 지연 개선 수단이지만 패킷 수 증가와 함께 봐야 합니다.

자주 하는 오해

오해바로잡기
SO_REUSEADDR은 무조건 필수환경/OS 정책에 따라 SO_EXCLUSIVEADDRUSE가 더 적합할 수 있음
TCP_NODELAY는 항상 켜야 정답트래픽 패턴에 따라 비용/효과가 달라짐
keepalive만 켜면 연결 관리 끝게임은 앱 heartbeat가 핵심

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

  • 개발/운영 환경에서 포트 재사용 정책을 어떻게 다르게 가져갈 것인가?
  • TCP_NODELAY를 켰을 때 얻는 이점과 잃는 것은 무엇인가?
  • 버퍼 크기 튜닝 결과를 어떤 지표로 검증할 것인가?

profile
李家네_공부방

0개의 댓글