요구사항 모음
- 모든 씬에서 서버와 통신을 한다
- 웹서버와 소켓서버를 둘 다 사용할 예정이다
- 데이터의 송수신 규격은 항상
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
에 선언되어있는 UnityWebRequest
와 Coroutine
을 사용해 구현한 비동기식 웹서버이다.
Coroutine
은 이 클래스를 갖고 있는 네트워크 모듈의 참조를 이용해 사용한다
Get
과 Post
함수 모두 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
{
// 응답이 실패한 경우 처리하는 로직 작성
}
});