[Unity Server] # 5 - Response from server to client

qweasfjbv·2025년 2월 13일

UnityServer

목록 보기
5/5
post-thumbnail

개요


클라이언트에서 서버로 정보를 보낸 후에, 서버에서 보내는 응답을 받아 처리하는 기능을 추가해 보겠습니다.

구현


테스트 케이스 작성

우선 Ubuntu 서버에 있는 로컬 DB에 테스트를 위한 랜덤 데이터들을 만들어줍니다.

DELIMITER $$

CREATE PROCEDURE InsertRandomData(IN cnt INT)
BEGIN
    DECLARE i INT DEFAULT 0;
    WHILE (i < cnt) DO
        INSERT INTO results (UserId, StageIdx, CycleCount, ButtonCount, KillCount) 
        VALUES 
        (FLOOR(RAND() * 10),
         FLOOR(RAND() * 10),
         FLOOR(RAND() * 100),        
         FLOOR(RAND() * 25),          
         FLOOR(RAND() * 100));        
        SET i = i + 1;
    END WHILE;
END $$

DELIMITER ;

CALL InsertRandomData(100);	-- 랜덤이라 pkey가겹쳐서 100개가 생성되지는 않음
CALL InsertRandomData(100);
CALL InsertRandomData(100);


DB에서 데이터 가져오기

		private ServerResultData GetServerResultData()
		{
			Debug.Log("RESULT DATA");
			ServerResultData resultData = new ServerResultData();
			resultData.Set();

			using (MySqlConnection conn = new MySqlConnection(Constants.DB_CONN_STR))
			{
				try
				{
					conn.Open();
					string query = "SELECT StageIdx, CycleCount, ButtonCount, KillCount" +
						" FROM results;";

					using (MySqlCommand cmd = new MySqlCommand(query, conn))
					{
						using (MySqlDataReader reader = cmd.ExecuteReader())
						{
							while(reader.Read()){
								int stageIdx = reader.GetInt32("StageIdx");
								int cycleCount = reader.GetInt32("CycleCount");
								int buttonCount = reader.GetInt32("ButtonCount");
								int killCount = reader.GetInt32("KillCount");
								resultData.InsertData(stageIdx, cycleCount, buttonCount, killCount);

								Debug.Log($"{stageIdx}, {cycleCount}, {buttonCount}, {killCount}");
							}
						}
					}

					return resultData;
				}
				catch (Exception ex)
				{
					Debug.LogError("Error: " + ex.Message);
				}
			}
			return null;
		}

DB의 정보를 읽고, resultData에 저장하면서 Log를 찍는 함수입니다.
이대로 Server에서 데이터를 보내는 부분과 Client에서 받는 데이터를 알맞게 수정해 준 뒤에 테스트를 해보겠습니다.

위와같이 우분투 서버에서 로그가 잘 찍히는걸 확인할 수 있고,

클라이언트에서도 정보를 잘 받은걸 확인할 수 있습니다.


Visualization

클라이언트에서 이렇게 받은 데이터를 persistentDataPath에 json파일을 만들어서 저장하고, 필요할때 동적으로 로드해서 데이터를 받아오겠습니다.

        /// <summary>
        /// 서버에서 받은 결과 데이터를 저장
        /// 그래프를 그리는데 사용
        /// </summary>
        public void SaveServerResults(ServerResultData data)
		{
			string json = JsonUtility.ToJson(data, true);
			File.WriteAllText(serverResultPath, json);
		}

데이터의 로드/저장을 다루는 스크립트에 해당 함수를 선언해준 뒤에 ClientManager에서 호출해줍니다.

		private async void SendMessageAsync(byte[] buff)
		{
			TcpClient client = new TcpClient(Constants.IP_ADDR_INHO, Constants.PORT_VM_TCP);
			NetworkStream stream = client.GetStream();

			await stream.WriteAsync(buff, 0, buff.Length);
			await stream.FlushAsync();

			byte[] buffer = new byte[1024];
			int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
			
			// 데이터를 Json으로 저장
			Managers.Data.SaveServerResults(Serializer.ByteArrayToObject<ServerResultData>(buffer));

			client.Close();
		}

이제 저장이 되었으니 사용만 하면 됩니다.


        /// <summary>
        /// Stage에 해당하는 결과들을 받아옵니다.
        /// </summary>
        public CountResultData GetServerResults(int stageIdx)
        {
            string json = File.ReadAllText(serverResultPath);
			ServerResultData data = JsonUtility.FromJson<ServerResultData>(json);
            return data.datas[stageIdx];
        }

한 번에 한 스테이지의 정보만 필요하기 때문에 적절하게 Getter를 선언해줍니다.
UI와 데이터를 좀 더 실제같이 꾸며준 뒤에 위에서 만든 Getter 를 통해 그릴 수 있는 로직을 만들고 테스트를 해보겠습니다.

마무리


지금까지 한 것들을 종합하면 실시간 통신이 필요없는 웹 서버와 비슷합니다.

  • 포트포워딩 및 TCP 통신을 통해 데이터 송수신 가능
  • 필요한 데이터를 직렬화 및 압축하여 최소한의 데이터로 통신가능
  • 서버에서 받은 데이터는 시뮬레이션 및 MySQL 에 업데이트
  • 클라에서 받은 데이터는 Json으로 저장 및 실시간 로드해서 그래프로 시각화

이제 네트워크 상에서 여러가지 테스트를 진행하면서 부족한 부분을 채워나가겠습니다.

0개의 댓글