일기

Socket.io를 활용한 통신 프로젝트

Realuda72 2024. 12. 20. 12:48

Socket.io를 사용해 간단한 프로젝트를 만들었다.

 

서버는 Node.js로, 클라이언트는 Unity로 만들었다.

 

유니티에는 공식 Socket.io 패키지가 없었기 때문에, 비공식 패키지를 사용했다.

https://bestdocshub.pages.dev/

 

Best Packages Documentation Hub

The ULTIMATE Best Bundle Discover the pinnacle of Unity communication tools with The Ultimate Best Bundle. Packing all my prized packages and protocols, it's the one-stop solution for all your connectivity needs. Dive into web-centric interactions, embrace

bestdocshub.pages.dev


<README>

개요

우주 공간에서 날아오는 운석을 피해 오래 살아남으면 되는 간단한 게임입니다.

서버

서버는 Node.js로 작성했습니다.

  • 게임에 필요한 정보(스테이지, 아이템, 아이템 해금)를 json형태로 가지고 있습니다.
  • 서버에 접속한 클라이언트의 UID, 스테이지에 관한 정보를 가지고 있습니다.
  • 유저가 보낸 패킷을 packetId로 구분하여 적절한 핸들러로 처리합니다.

서버가 처리하는 핸들러는 아래와 같습니다.

  • 게임 데이터 전송. 클라이언트가 접속하고 게임 데이터를 요청하면 서버에 있는 게임 데이터를 전송합니다.
  • 게임 시작. 클라이언트가 게임 시작을 요청하면, 클라이언트의 UID와 게임 시작 정보를 저장합니다.
  • 게임 종료. 클라이언트가 게임 종료를 요청하면, 클라이언트가 보낸 점수와 시간 정보로 데이터를 검증합니다.
  • 스테이지 이동. 클라이언트가 일정 점수에 도달해 스테이지를 이동을 요청하면, 클라이언트가 보낸 점수와 시간 정보로 데이터를 검증합니다.
  • 아이템 획득. 클라이언트가 아이템 획득을 요청하면, 현재 스테이지에 맞는 아이템 점수를 획득합니다.
  • 채팅 메시지. 클라이언트가 채팅 메시지를 보내면, 모든 클라이언트에게 메시지를 브로드캐스트합니다.

클라이언트

클라이언트는 Unity로 만들었습니다. Unity에는 공식 Socket.io 패키지가 없었기 때문에 비공식 Socket.io 패키지를 사용했습니다. https://bestdocshub.pages.dev/

클라이언트는 게임 과정에서 서버에 패킷을 보내 요청하고, 응답을 받아 처리합니다.

클라이언트가 처리하는 핸들러는 아래와 같습니다.

  • 게임 데이터 요청. 게임을 시작하기 전에 서버에 게임 데이터를 요청합니다.
  • 게임 시작 요청. 게임을 시작하기 위해 서버에 요청합니다. 서버로부터 응답이 오면 게임을 시작합니다.
  • 게임 종료 요청. 게임을 종료하기 위해 서버에 요청합니다. 서버로부터 응답이 오면 게임을 종료합니다.
  • 스테이지 이동 요청. 일정 점수에 도달하면 다음 스테이지로 이동합니다. 서버로부터 응답이 오면 스테이지를 이동합니다.
  • 아이템 획득. 아이템을 획득하면 서버에 요청합니다. 서버로부터 응답이 오면 점수를 획득합니다.
  • 채팅 메시지. 채팅창에 메시지를 입력하고 엔터를 누르거나 버튼을 누르면 메시지를 전송합니다. 전송된 메시지를 브로드캐스트 되어 모든 클라이언트에 전송됩니다.

 Unity는 C#을 사용하고, Node.js는 JavaScript를 사용한다.

 서버에서 객체 형태로 메시지를 보내면, 클라이언트는 메시지를 파싱해서 사용해야 한다. 파싱만 하는거라면 쉽다. 유니티는 JSON을 파싱해주는 유틸리티가 기본으로 제공되기 때문이다. 그러나 문제는 자바스크립트의 자유로운 자료형(?)이었다. 서버가 주는 메시지의 자료형을 특정할 수 없었기 때문에, 우선은 메시지를 일괄적으로 string으로 받고 패킷 아이디에 따라 파싱해야했다. 서버쪽 코드에 자료형을 명시하지 않기 때문에 메시지를 파싱할 때 양쪽 코드를 왔다갔다 보느라 머리가 아팠다.

 처음에 이에 대한 고려가 없었기 때문에 패기롭게 유니티로 클라이언트를 만들고자 했다. 지금은 가장 후회하는 부분이자 보람찬 부분 중 하나이다. 차라리 캔버스를 공부해서 만드는게 더 쉽지 않았을까? 클라이언트는 조금 낯설지만 패킷 핸들링에서 시간을 많이 절약할 수 있었을 것이다.

 

 클라이언트가 서버로 요청을 보내면 서버는 데이터를 검증해서 클라이언트에 응답을 보낸다. 이 과정에서 검증에 성공했다면 정상적으로 게임이 진행되지만, 검증에 실패했을 경우에는 어떻게 처리해야 할까? 지금은 클라이언트에서 별다른 조치를 취하지 않는다. 검증에 실패한 경우 클라이언트에서는 일어나야 할 일이 일어나지 않을 뿐, 게임은 계속 진행된다. 이런 경우에 클라이언트는 어떻게 처리해야 할지 생각해봐야겠다.

 

 아쉬운점은 서버 프로그램이 강의에서 했던 스켈레톤 코드에서 크게 벗어나지 않은 것이다. 클라이언트에서 고생할 시간에 서버쪽을 더 고민했으면 좋았겠다. 만들고보니 최종 결과물에서 필수 구현 요구사항이 하나 빠져있었다. 스테이지별로 획득하는 점수가 다르게 해야했다. 아이템도 아이템id에 따라 다른 아이템을 생성하는게 아니라 아이템이 주는 점수만 달르게 했다.

 

 깃 관리를 소홀히 했다. 최종 결과물을 제출하기 고장 10시간 전에 첫 리포를 생성했고, 커밋도 몇개 없다. 중간중간 집중력을 잃고 작업에 해메이던 때가 있었는데, 진작에 리포를 파고 깃으로 관리했으면 작업 기록이 남으니까 이정표가 되어주었을 것이다. 이미 이전 프로젝트에서도 겪었던 문제인데 또 같은 문제를 겪어서 아쉽다.

 

 프로젝트 초반에 시간이 넉넉하다고 생각해 많이 게을렀다. 결국 마감일이 닥치니 밤을 새서 간신히 완성(?)했다. 결과물은 처참하다. 기본 요구사항도 빠졌고, 프로젝트 관리도 엉망이다. 제대로 기획되지 않은 탓에 코드도 중구난방이다. 이런 개발자가 있을까?

'일기' 카테고리의 다른 글

(JavaScript) 바탕화면 정리  (0) 2024.12.18
라우팅  (0) 2024.12.16
(JavaScript) 성격 유형 검사하기  (0) 2024.12.16
Classless Inter Domain Routing(CIDR)  (0) 2024.12.15
Classful IP Addressing  (0) 2024.12.14