유니티 웹서버 통신

정선호·2023년 5월 31일
0

Original

목록 보기
3/5

요구사항 모음

  • 모든 씬에서 서버와 통신을 한다
  • 웹서버와 소켓서버를 둘 다 사용할 예정이다
  • 데이터의 송수신 규격은 항상 Json String을 사용한다
  • 비동기적으로 처리해야 한다

네트워크 모듈

  • 싱글턴으로 만들어진 전역적인 모듈로 네트워킹을 필요로 하는 모든 클래스에서 해당 모듈을 사용해 통신을 주고받을 수 있도록 만들었다
  • 네트워크 모듈 안에는 웹서버 또는 소켓 서버에 통신할 수 있는 핸들러 클래스를 선언한다.
    • 이들은 비동기 통신을 위해 Coroutine을 사용해야 하므로 MonoBehaviour를 상속받고 있는 네트워크 모듈을 참조하도록 한다
using UnityEngine;

namespace Network
{
    public class NetworkModule : MonoBehaviour
    {
        #region Public values

        public static NetworkModule Instance;

        public WebHandler WebHandler;
        
        #endregion

        #region Mono Methods

        private void Awake()
        {
            if (Instance != null && Instance != this)
                Destroy(this.gameObject);
            else
            {
                Instance = this;
                DontDestroyOnLoad(Instance);
            }

            WebHandler = new WebHandler(this);
        }

        #endregion
    }
}

웹 핸들러

  • UnityEngine.Networking에 선언되어있는 UnityWebRequestCoroutine을 사용해 구현한 비동기식 웹서버이다.
    • Coroutine은 이 클래스를 갖고 있는 네트워크 모듈의 참조를 이용해 사용한다
  • GetPost함수 모두 Json String형식을 사용해 데이터를 주고받는다
    • Json String과 구조체를 컨버팅하는 함수는 따로 구현하였다.
  • UnityWebRequest www = UnityWebRequest.Get(url);로 웹소켓을 열었으면 꼭 www.Dispose();로 소켓을 닫아주자. 메모리 누수가 생긴다.
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

namespace Network
{
    public class WebHandler
    {
    #region Public Methods

    public WebHandler(NetworkModule context)
    {
        _context = context;
    }

    #endregion

    #region Public Methods


    /// <summary>
    /// 웹서버에서 Json데이터를 받아오는 함수, 서버의 응답에 대한 처리도 실시한다
    /// </summary>
    public void Get(string url, Action<string> callback)
    {
        _context.StartCoroutine(GetRequestCoroutine(url, callback));
    }
    

    /// <summary>
    /// 웹서버에 Json데이터를 보내는 함수, 서버의 응답에 대한 처리도 실시한다
    /// </summary>
    public void Post(string url, string jsonData, Action<string> callback)
    {
        _context.StartCoroutine(PostRequestCoroutine(url, jsonData, callback));
    }

    #endregion
    
    #region Private values

    private NetworkModule _context;

    #endregion

    #region Private Methods
    
    private IEnumerator GetRequestCoroutine(string url, Action<string> callback)
    {
        UnityWebRequest www = UnityWebRequest.Get(url);

        yield return www.SendWebRequest();

        if (www.result != UnityWebRequest.Result.Success)
        {
            Debug.LogError("GET request error: " + www.error);
            callback?.Invoke(null);
        }
        else
        {
            string response = www.downloadHandler.text;
            Debug.Log("GET request successful!");
            Debug.Log("Response: " + response);
            callback?.Invoke(response);
        }
        
        www.Dispose();
    }
    
    private IEnumerator PostRequestCoroutine(string url, string jsonData, Action<string> callback)
    {
        UnityWebRequest www = new UnityWebRequest(url, "POST");
        byte[] jsonBytes = System.Text.Encoding.UTF8.GetBytes(jsonData);

        www.uploadHandler = new UploadHandlerRaw(jsonBytes);
        www.downloadHandler = new DownloadHandlerBuffer();
        www.SetRequestHeader("Content-Type", "application/json");

        yield return www.SendWebRequest();

        if (www.result != UnityWebRequest.Result.Success)
        {
            Debug.LogError("POST request error: " + www.error);
            callback?.Invoke(null);
        }
        else
        {
            string response = www.downloadHandler.text;
            Debug.Log("POST request successful!");
            Debug.Log("Response: " + response);
            callback?.Invoke(response);
        }
        
        www.Dispose();
    }

    #endregion
    }
}
  • 이를 사용하는 클라이언트는 Action<string> callback을 외부에서 델리게이트 함으로써 외부 클래스에서 데이터를 사용할 수 있게 된다
// Get 사용 예시
NetworkModule.Instance.WebHandler.Get(url, (response) =>
{
    if (response != null)
    {
        // 응답을 처리하는 로직 작성
    }
    else
    {
        // 응답이 실패한 경우 처리하는 로직 작성
    }
});

// Post 사용 예시
NetworkModule.Instance.WebHandler.Post(url, jsonData, (response) =>
{
    if (response != null)
    {
        // 응답을 처리하는 로직 작성
    }
    else
    {
        // 응답이 실패한 경우 처리하는 로직 작성
    }
});
profile
학습한 내용을 빠르게 다시 찾기 위한 저장소

0개의 댓글