dh_0e

[Project] 멀티 플레이 TCP 서버 구현하기 (개인과제) 본문

내일배움캠프/Project

[Project] 멀티 플레이 TCP 서버 구현하기 (개인과제)

dh_0e 2024. 7. 10. 23:33

이번 주차 강의는 이해하기 꽤 어려웠다. 코드 따라가기도 벅찬데 이해까지 하려니까 정신이 나갈 뻔했지만, 이번 과제를 하면서 모두 이해한 것 같아 뿌듯했다. 도전 기능 중, latency를 이용한 추측항법 적용은 Unity와 C#에 대한 이해도가 필요하여 구현하지 못했다.. 나중에 제대로 공부하면 다시 구현해 봐야겠다.

 

필수 기능 정의

더보기
  • 우리가 만들어야 할 내용들을 체크리스트로 정리해봅시다.
    • [ ] 프로젝트 구성
      • [ ] 게임 인스턴스 생성
    • [ ] 유저 접속
      • [ ] 유저 인스턴스 생성
      • [ ] 위치 패킷 교환
  1. 꼭 ‘npm init -y’ 부터 프로젝트를 생성해서 만들어 보세요.
    1. 프로젝트를 처음부터 세팅하여 만들어보는 경험은 큰 자산이 됩니다.
    2. 강의를 들으며 완성한 코드들을 참고로 하여도 좋지만 복사, 붙여넣기는 하지않는 것으로 하세요.
    3. 다시 한번 더 코드를 작성하면서 전체적인 프로젝트를 이해해보세요.
  2. 프로젝트의 구성 과 게임 인스턴스 생성
    1. 이번 과제에서 진행하는 내용이 강의에서 배운 내용보다 프로젝트의 규모가 작습니다.
    2. 필수 기능에서는 DB 사용은 하지 않고, 게임 인스턴스도 서버가 기동될 때 1개만 생성이 되도록해봅시다.
  3. 유저 접속
    1. 고유한 ID인 deviceId 와 함께 클라이언트는 서버로 접속시도를 합니다. 1번에서 생성한 게임 인스턴스에서 유저 인스턴스를 관리할 수 있도록 등록합니다.
    2. initialPacket을 교환한 이후부터는 위치 업데이트 패킷을 지속적으로 서버에 전달합니다.
    3. 환경변수 server.host를 0.0.0.0 으로 변경해야 모든 주소로 부터 접속을 받을 수 있습니다.

 

도전 기능 정의

더보기
  • DB 연동
    • 같은 device id 를 가진 유저가 재접속 했을 경우 마지막 위치에서 재접속 되어야합니다. (기획)
      • 클라이언트에서 해당 코드는 작성되어 있지 않습니다.
    • DB(MySQL)을 연동하여 유저 게임 종료 시 유저의 마지막 위치를 저장합니다.
      • 유저의 device id 를 사용하여 유저 정보를 저장해야 합니다.
  • Latency 를 이용한 추측항법 적용
    • C# 과 유니티에 대한 이해가 있어야 가능한 과제입니다.
    • 클라이언트 코드를 유니티를 통해 확인해보면 Game Manager 스크립트에서 Latency를 관리하고 있는 것을 확인 할 수 있습니다. 이 Latency 값을 조절하면 Task.Delay 함수에 의해 모든 패킷이 ms 단위로 늦게 전송이 되게 됩니다.
    • 현재 클라이언트 코드의 상태로 보면 나의 캐릭터 위치는 클라이언트에서 받는 인풋에 의존하고 있고 다른 플레이어들의 위치 데이터만을 받아 화면에 보여주고 있습니다.
    • 추측항법을 적용하여 위치를 예측하여 보내준다면 모든 유저에게 같은 위치로 보여야 하기 때문에 나의 캐릭터 위치도 서버에 의존하여야 합니다.
    • 계산을 위한 플레이어의 속도는 Player 스크립트에서 관리하고 있습니다.
    • 계산을 하기 위해서는 latency를 기록하여야 하는데 과제의 ‘필수’기능까지는 latency를 서버에서 저장하고 있지 않습니다. 클라이언트에서 서버로 latency를 보내고 받기 위해서 패킷 정의를 수정하고 데이터를 저장하는 과정이 추가되어야합니다.
      • DB 연동
        • 같은 device id 를 가진 유저가 재접속 했을 경우 마지막 위치에서 재접속 되어야합니다. (기획)
          • 클라이언트에서 해당 코드는 작성되어 있지 않습니다.
        • DB(MySQL)을 연동하여 유저 게임 종료 시 유저의 마지막 위치를 저장합니다.
          • 유저의 device id 를 사용하여 유저 정보를 저장해야 합니다.
      • Latency 를 이용한 추측항법 적용
        • C# 과 유니티에 대한 이해가 있어야 가능한 과제입니다.
        • 클라이언트 코드를 유니티를 통해 확인해보면 Game Manager 스크립트에서 Latency를 관리하고 있는 것을 확인 할 수 있습니다. 이 Latency 값을 조절하면 Task.Delay 함수에 의해 모든 패킷이 ms 단위로 늦게 전송이 되게 됩니다.
        • 현재 클라이언트 코드의 상태로 보면 나의 캐릭터 위치는 클라이언트에서 받는 인풋에 의존하고 있고 다른 플레이어들의 위치 데이터만을 받아 화면에 보여주고 있습니다.
        • 추측항법을 적용하여 위치를 예측하여 보내준다면 모든 유저에게 같은 위치로 보여야 하기 때문에 나의 캐릭터 위치도 서버에 의존하여야 합니다.
        • 계산을 위한 플레이어의 속도는 Player 스크립트에서 관리하고 있습니다.
        • 계산을 하기 위해서는 latency를 기록하여야 하는데 과제의 ‘필수’기능까지는 latency를 서버에서 저장하고 있지 않습니다. 클라이언트에서 서버로 latency를 보내고 받기 위해서 패킷 정의를 수정하고 데이터를 저장하는 과정이 추가되어야합니다.

 

게임 작동 화면

 

 

프로젝트 Github URL: https://github.com/znfnfns0365/tcp_game

 

GitHub - znfnfns0365/tcp_game

Contribute to znfnfns0365/tcp_game development by creating an account on GitHub.

github.com

  • Readme 파일에 서버 링크(닫힘), 기능 정의, 바이트 배열 구조, 패킷 구조, 핸들러 구조, 파일 구조 등이 나와있다.

 

Trouble Shooting

 서버에서 클라이언트로 usersLocationPacket을 보낼 때, 사용자 모두의 좌표 정보를 보냈더니 캐릭터가 2개가 생겨 아무 버튼을 누르지 않았는데도 오른쪽으로 이동하는 현상이 생겼다. 이는 클라이언트에 자신의 위치 정보가 있는데도 패킷을 받아 한 번 더 갱신하다 자기 자신이 2개가 생성되어 왼쪽으로 계속 이동하려는 버그였다. 이는 locationData에 filter를 씌워 패킷을 보내는 기준인 userId를 제외하고 패킷을 보냈더니 해결되었다.

 

 MySQL로 유저 정보를 저장하고, 유저가 재접속 시 위치 정보를 불러오는 과정을 git Bash에서 서버를 열 때, 다시 설정하여야 했는데 꽤나 애먹었다. MySQl 서버를 ubuntu에서 생성하여 권한을 재정의하여 이를 해결하였다.

 

 서버가 클라이언트에게 패킷을 받고 다시 보내는 과정에서 클라이언트를 강제 종료할 경우 없는 꺼진 소켓에 패킷을 보내게 되므로 에러가 발생한다. 이를 해결하고자 clients라는 이름의 소켓을 key 값으로 마지막 수정 시간을 value 값으로 하는 Map 객체를 만들어 소켓을 저장하고 socket.on('end')가 호출되자마자 clients에 해당 소켓을 삭제한 뒤, 패킷을 보낼 때마다 clients에 소켓이 존재하나 물어보고 없다면 보내지 않게 수정했다... 수정했지만 아직도 한 번씩 오류가 발생한다. 현재 클라이언트에서 1초에 30번씩 패킷을 보내는데 이 주기를 짧게 설정하면 오류가 발생하는 빈도를 줄일 수 있을 거라 예상한다..