나만의 작은 도서관
[TIL][C++] 250503 MMO 서버 개발 10일차: 여러 쓰레드가 하나의 소켓에 대해 send를 하려는 상황이 발생하는가?, 이동 방식에 따른 동기화 방식 본문
Today I Learn
[TIL][C++] 250503 MMO 서버 개발 10일차: 여러 쓰레드가 하나의 소켓에 대해 send를 하려는 상황이 발생하는가?, 이동 방식에 따른 동기화 방식
pledge24 2025. 5. 4. 01:17주의사항: 해당 글은 일기와 같은 기록용으로, 다듬지 않은 날것 그대로인 글입니다.
여러 스레드가 하나의 소켓에 대해 send를 하려는 상황이 발생하는가?
recv의 경우
- 기본적으로 TCP 통신에서는 클라이언트-서버 구조에서 상대 호스트와 통신할 때 송신 횟수(send)가 수신 횟수(recv) 보다 많다. 왜냐하면 TCP에서의 수신은 데이터를 한 번에 가져오기 때문이다. 즉, 송신을 3번 해도, 수신 한 번으로 데이터를 전부 가져올 수 있다는 것이다.
- 이러한 이유 때문에 하나의 소켓에 대해 수신 이벤트를 여러 개 등록하지 않고 하나만 등록해 두어도 성능이 준수하다. 어차피 OS가 관리하는 수신 버퍼가 꽉 차기 전에 가져오기만 하면 되기 때문이다.
본론: send의 경우
- send의 경우 recv처럼 이미 존재하는 데이터를 복사해서 가져오는 것이 아닌, 만든 데이터를 넣어주는 방식이다. 즉, 스레드가 send를 시도한다면 이 스레드는 현재 흐름에서 생성한 한 종류의 송신 데이터를 송신하려 할 것이다.
- 예를 들어, Room 상태 갱신 정보를 Tick 단위로 broadcast 할 때 발생하는 송신 데이터가 여러 개 있을 것이고, Room이랑 별개인 귓속말 전달과 같은 송신 데이터도 여러 개 있을 것이다. Room 상태 갱신의 경우, 수신 이벤트가 발생하지 않아도 클라이언트에게 보내줘야 할 데이터이기 때문에, 수신 이벤트에 따른 송신과는 흐름과는 독립적이므로 각 스레드(Room broadcast 스레드, 귓속말 처리 스레드)가 같은 소켓에 대해 WSASend 하는 경우가 발생할 수 있다. 다른 말로, 송신 이벤트가 중첩(overlapped)될 수 있다는 것이다.
결론
- 수신에 의한 송신 흐름과 수신하지 않아도 송신해야 하는 흐름이 따로 존재하기 때문에, 여러 스레드가 같은 소켓에 대해 송신하는 상황이 발생할 수 있다.
이동 방식에 따른 동기화 방식
- 게임 안에서 캐릭터 이동 방식은 크게 2가지로, 1) 키보드 이동과 2) 마우스 클릭 이동이 있다. 1) 키보드 이동의 경우 키 입력 데이터가 이동할 위치가 아닌 방향에 대한 정보가 입력되기 때문에, 방향키를 뗄 때까지 주기적으로 패킷을 보내게 된다.
- 이때 키보드 이동 동기화를 서버 주도로 하면, 클라이언트는 RTT만큼 뒤에 이동에 대한 반응을 얻기 때문에 사용자 경험이 떨어진다. 따라서 키보드 이동 같은 경우 클라이언트 주도로 이동을 하고, 서버는 검증만 하는 방식으로 한다.(+롤백)
- 반면 마우스 클릭 이동은 클릭 할 때만 이동할 위치 정보를 서버에게 전송하기 때문에 이동 패킷 전송 빈도도 키보드보다 적고, 클라도 서버로부터 response 패킷을 한 번만 받으면 되기 때문에 서버-주도 방식으로 이동 동기화를 해도 사용자 경험이 떨어지지 않는다. (물론, 중간중간 이동 위치에 대한 검증 패킷은 왔다 갔다 할 것이다)
결론
- 키보드 이동은 클라-주도, 마우스 클릭은 서버-주도로 이동 동기화를 한다.