[Unity] UnityWebRequest를 사용한 통신 로직 구현

Date:     Updated:

카테고리:

태그:

상용화가 목적인 프로젝트에서 클라이언트와 서버가 통신을 하는 것은 필수적입니다.

통신에는 여러종류가 있지만, 이번에 구현한 통신방식은 HTTP 통신 입니다.

Winform을 할 때는 MySQL.dll를 임포트하여 MySQLConnection을 사용하여 구현했습니다. 하지만, 게임에서는 통신중에 다른 로직이 멈추면 안되기에 비동기 처리를 권장하고 있었습니다. 그리하여 UnityWebRequestCoroutine을 사용하여 비동기로 구현하였습니다.

또한, Newtonsoft.Json패키지를 사용하였습니다. 해당 패키지는 Window - PackageManager 에서 이름으로 검색을 선택 한 후, com.unity.nuget.newtonsoft-json 을 입력하면 됩니다.

package Manager

Model 클래스 만들기

본 예제는 MVC 패턴을 기준으로 작성되었습니다. 우선 데이터를 담을 Model 클래스를 만듭니다.

경로는 Asset/Model/User 입니다.

🗅 class UserModel

using Newtonsoft.Json;

namespace Model.User
{
    [System.Serializable]
    public class UserModel
    {
        [JsonProperty("user_code")]
        public string UserCode;

        [JsonProperty("user_nick")]
        public string UserNick;
    }
}

그리고 서버에서 results 라는 키값을 넣은 json배열을 보낼것이기 때문에 이 results 를 담을 수 있는 제네릭 모델을 만들어 줍니다.

경로는 Asset/Model/Result 입니다.

🗅 class ResultModel

namespace Model.Result
{
    [System.Serializable]
    public class ResultModel<T>
    {
        public T[] results;
    }
}

Repository 클래스 만들기

이제 직접 데이터베이스에 접근할 로직을 구현하기 위해 Repository 클래스를 구현 합니다. (이름은 생각나는대로 했는데 혹시 더 좋은 이름이 있다면 추천해주세요. ) 또한, User 정보에 접근하기 위한 서버 주소도 해당 repository에서 관리하게 됩니다.

경로는 Asset/Script/DataAccess/User 입니다.

여기서 CheckNull함수는 디비에서 넘어올 때 값이 NULL이면 빈 문자열을 반환하는 메서드 입니다.

아래에는 DeserializeObject()를 사용하여 클래에 바로매핑하는 방식과, JsonObject 를 받아서 해체하는 방식 두가지로 작성하였습니다.

🗅 class UserRepository

using Model.Result;
using Model.User;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UIElements;
using Common.Method;

namespace DataAccess.User
{

    public class UserRepository
    {
        private CommonMethod method = new CommonMethod();

        private string url = "https://successlist.mycafe24.com/successlist/php/SELECT_USER.php";

        public IEnumerator SELECT_USER(string _userCode, Action<bool, UserModel> _action)
        {
            WWWForm form = new WWWForm();
            form.AddField("userCode", _userCode);

            using (UnityWebRequest request = UnityWebRequest.Post(url, form))
            {
                yield return request.SendWebRequest();

                if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
                {
                    _action(false, null);
                    //로깅작업 생략
                }
                else
                {
                    try
                    {
                        //결과 json
                        JObject jsonResponse = JObject.Parse(request.downloadHandler.text);

                        //하나씩 뜯는 경우
                        JArray resultsArray = (JArray)jsonResponse["results"];

                        UserModel model = new UserModel();

                        string userCode = method.CheckNull(resultsArray[0]["user_code"].ToString());
                        string nickName = method.CheckNull(resultsArray[0]["user_nick"].ToString());

                        model.UserCode = userCode;
                        model.UserNick = nickName;

                        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

                        //클래스에 바로 대입하는 경우
                        string jsonResponse1 = request.downloadHandler.text;
                        ResultModel<UserModel> jsonResult = JsonConvert.DeserializeObject<ResultModel<UserModel>>(jsonResponse1);

                        // 결과 확인
                        UserModel userModel = new UserModel();


                        //json 배열로 들어왔을 때 foreach 사용
                        foreach (var user in jsonResult.results)
                        {
                            userModel.UserCode = user.UserCode;
                            userModel.UserNick = user.UserNick;
                        }

                        _action(true, model);
                    }
                    catch (Exception ex)
                    {
                        _action(false, null);
                        //로깅작업 생략
                    }
                }
            }
        }

        public IEnumerator INSERT_USER() { yield return null; }
        public IEnumerator UPDATE_USER() { yield return null; }
        public IEnumerator DELETE_USER() { yield return null; }
    }
}

해당 Repository는 데이터 베이스에 접근하여, 정상적으로 값을 받아온 경우에는 true를, 값을 받아오지 못한 경우에는 false를 반환하게 됩니다.

또한 UserModel에 정보를 넣어서 Action에서 반환하도록 해줍니다.

실행부

이제 준비가 끝났으니, 실행부에서 실행을 해봅니다.

실행부에서는 통신이 필요할 때, 해당 Repository의 함수를 참조하도록 합니다.

🗅 class ConnectionTest

using System;
using System.Collections;
using UnityEngine;
using DataAccess.User;

public class ConnectionTest : MonoBehaviour
{
    private void Start()
    {
        UserRepository userRepository = new UserRepository();
        StartCoroutine(userRepository.SELECT_USER("tICzO", (success, userModel) =>
        {              
            if (success)
            {
                SomeAction(userModel.UserCode, userModel.UserNick);
            }
            else
            {
                Debug.Log("네트워크 연결 실패");
            }
        }));
    }

    private void SomeAction(string _userCode, string _userNick)
    {
        Debug.Log(_userCode);
        Debug.Log(_userNick);
    }
}

여기서 코루틴에서 실행되며 반환된 success 값을 기준으로 통신에 성공하였을 때, 실패하였을 때 처리할 로직을 나누어서 구현하도록 합니다.

혹시 잘못된 부분이나, 수정할 부분이 있다면, 언제든지 댓글로 피드백 부탁드립니다!

Unity 카테고리 내 다른 글 보러가기

댓글 남기기