본문 바로가기

프로그램/유니티 네트워크

[유니티 네트워크] UdpServer, UdpClient 구조체 전송 (Socket)

728x90
반응형

1. 내용

 (1) 권장 포트 번호 : 49152 ~ 65535

 

포트 번호

내용

0

사용하지 않음.

1 ~1023

잘 알려진 포트(Well-known port)

1024 ~ 49151

등록된 포트(Registered port)

49152 ~ 65535

동적 포트(Dynamic port)

 

 (2) 전송 패키지 사이즈

 Udp는 이론상으로는 65507 byte까지 보낼수 있지만, 내부 통신이 아닌 경우 1024 byte이내를 권장합니다.

 

 (3) 소스 내용

  - 유니티와 유니티, 또는 C#과의 통신, 또는 C++와의 통신

  - 클래스 : Socket

  - 개체 직렬화 : Marshal

  - 전송 패킷 : 구조체 ↔ 바이트 배열

 

2. 소스

2.1 Server.cs

using System;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;

public class Server : MonoBehaviour
{
    private Socket m_Server;
    public int m_Port = 50001;
    public ToServerPacket m_ReceivePacket = new ToServerPacket();
    public ToClientPacket m_SendPacket = new ToClientPacket();
    private EndPoint m_RemoteEndPoint;

    void Start()
    {
        InitServer();
    }

    void Update()
    {
        Receive();
        Send();
    }

    void OnApplicationQuit()
    {
        CloseServer();
    }

    void InitServer()
    {
        // SendPacket에 배열이 있으면 선언 해 주어야 함.
        m_SendPacket.m_IntArray = new int[2];

        m_RemoteEndPoint = new IPEndPoint(IPAddress.Any, m_Port);
        m_Server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        m_Server.Bind(m_RemoteEndPoint);
        m_Server.Blocking = false;
    }

    void Receive()
    {
        int receive = 0;
        byte[] packet = new byte[1024];

        try
        {
            receive = m_Server.ReceiveFrom(packet, ref m_RemoteEndPoint);
        }

        catch (Exception ex)
        {
            //Debug.Log(ex.ToString());
            return;
        }

        m_ReceivePacket = ByteArrayToStruct<ToServerPacket>(packet);

        if (receive > 0)
        {
            DoReceivePacket(); // 받은 값 처리
        }
    }

    void DoReceivePacket()
    {
        Debug.LogFormat($"m_IntArray[0] = {m_ReceivePacket.m_IntArray[0]} " +
            $"m_IntArray[1] = {m_ReceivePacket.m_IntArray[1] } " +
            $"FloatlVariable = {m_ReceivePacket.m_FloatlVariable} " +
            $"StringlVariable = {m_ReceivePacket.m_StringlVariable}" +
            $"BoolVariable = {m_ReceivePacket.m_BoolVariable} " +
            $"IntlVariable = {m_ReceivePacket.m_IntVariable} ");
        //출력: m_IntArray[0] = 7 m_IntArray[1] = 47 FloatlVariable = 2020 StringlVariable = Coder ZeroBoolVariable = True IntlVariable = 13 
    }

    void Send()
    {
        try
        {
            SetSendPacket();

            byte[] sendPacket = StructToByteArray(m_SendPacket);
            m_Server.SendTo(sendPacket, m_RemoteEndPoint);
        }

        catch (Exception ex)
        {
            //Debug.Log(ex.ToString());
            return;
        }
    }

    void SetSendPacket()
    {
        m_SendPacket.m_BoolVariable = true;
        m_SendPacket.m_IntVariable = 13;
        m_SendPacket.m_IntArray[0] = 7;
        m_SendPacket.m_IntArray[1] = 47;
        m_SendPacket.m_FloatlVariable = 2020;
        m_SendPacket.m_StringlVariable = "Coder Zero";
    }

    void CloseServer()
    {
        if (m_Server != null)
        {
            m_Server.Close();
            m_Server = null;
        }
    }

    byte[] StructToByteArray(object obj)
    {
        int size = Marshal.SizeOf(obj);
        byte[] arr = new byte[size];
        IntPtr ptr = Marshal.AllocHGlobal(size);

        Marshal.StructureToPtr(obj, ptr, true);
        Marshal.Copy(ptr, arr, 0, size);
        Marshal.FreeHGlobal(ptr);
        return arr;
    }

    T ByteArrayToStruct<T>(byte[] buffer) where T : struct
    {
        int size = Marshal.SizeOf(typeof(T));
        if (size > buffer.Length)
        {
            throw new Exception();
        }

        IntPtr ptr = Marshal.AllocHGlobal(size);
        Marshal.Copy(buffer, 0, ptr, size);
        T obj = (T)Marshal.PtrToStructure(ptr, typeof(T));
        Marshal.FreeHGlobal(ptr);
        return obj;
    }
}

 

2.2 Client.cs

using System;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;

public class Client : MonoBehaviour
{
    private Socket m_Client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
    public string m_Ip = "127.0.0.1";
    public int m_Port = 50001;
    public ToServerPacket m_SendPacket = new ToServerPacket();
    public ToClientPacket m_ReceivePacket = new ToClientPacket();
    private IPEndPoint m_ServerIpEndPoint;
    private EndPoint m_RemoteEndPoint;

    void Start()
    {
        InitClient();
    }


    void Update()
    {
        Receive();
        Send();
    }

    void OnApplicationQuit()
    {
        CloseClient();
    }

    void InitClient()
    {
        // SendPacket에 배열이 있으면 선언 해 주어야 함.
        m_SendPacket.m_IntArray = new int[2];

        m_ServerIpEndPoint = new IPEndPoint(IPAddress.Parse(m_Ip), m_Port);
        IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 0);
        m_RemoteEndPoint = (EndPoint)ipEndPoint;
    }

    void SetSendPacket()
    {
        m_SendPacket.m_BoolVariable = true;
        m_SendPacket.m_IntVariable = 13;
        m_SendPacket.m_IntArray[0] = 7;
        m_SendPacket.m_IntArray[1] = 47;
        m_SendPacket.m_FloatlVariable = 2020;
        m_SendPacket.m_StringlVariable = "Coder Zero";
    }

    void Send()
    {
        try
        {
            SetSendPacket();

            byte[] sendPacket = StructToByteArray(m_SendPacket);
            m_Client.SendTo(sendPacket, sendPacket.Length, SocketFlags.None, m_ServerIpEndPoint);
        }

        catch (Exception ex)
        {
            //Debug.Log(ex.ToString());
            return;
        }
    }

    void Receive()
    {
        int receive = 0;
        if (m_Client.Available != 0)
        {
            byte[] packet = new byte[1024];

            try
            {
                receive = m_Client.ReceiveFrom(packet, ref m_RemoteEndPoint);
            }

            catch (Exception ex)
            {
                //Debug.Log(ex.ToString());
                return;
            }

            m_ReceivePacket = ByteArrayToStruct<ToClientPacket>(packet);

            if (receive > 0)
            {
                DoReceivePacket(); // 받은 값 처리
            }
        }
    }

    void DoReceivePacket()
    {
        Debug.LogFormat($"BoolVariable = {m_ReceivePacket.m_BoolVariable} " +
            $"IntlVariable = {m_ReceivePacket.m_IntVariable} " +
            $"m_IntArray[0] = {m_ReceivePacket.m_IntArray[0]} " +
            $"m_IntArray[1] = {m_ReceivePacket.m_IntArray[1] } " +
            $"FloatlVariable = {m_ReceivePacket.m_FloatlVariable} " +
            $"StringlVariable = {m_ReceivePacket.m_StringlVariable}");
        //출력: BoolVariable = True IntlVariable = 13 m_IntArray[0] = 7 m_IntArray[1] = 47 FloatlVariable = 2020 StringlVariable = Coder Zero
    }

    void CloseClient()
    {
        if (m_Client != null)
        {
            m_Client.Close();
            m_Client = null;
        }
    }

    byte[] StructToByteArray(object obj)
    {
        int size = Marshal.SizeOf(obj);
        byte[] arr = new byte[size];
        IntPtr ptr = Marshal.AllocHGlobal(size);

        Marshal.StructureToPtr(obj, ptr, true);
        Marshal.Copy(ptr, arr, 0, size);
        Marshal.FreeHGlobal(ptr);
        return arr;
    }

    T ByteArrayToStruct<T>(byte[] buffer) where T : struct
    {
        int size = Marshal.SizeOf(typeof(T));
        if (size > buffer.Length)
        {
            throw new Exception();
        }

        IntPtr ptr = Marshal.AllocHGlobal(size);
        Marshal.Copy(buffer, 0, ptr, size);
        T obj = (T)Marshal.PtrToStructure(ptr, typeof(T));
        Marshal.FreeHGlobal(ptr);
        return obj;
    }
}

 

2.3 Packets.cs

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
[Serializable]
public struct ToServerPacket
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
    public int[] m_IntArray;
    public float m_FloatlVariable;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string m_StringlVariable;
    [MarshalAs(UnmanagedType.Bool)]
    public bool m_BoolVariable;
    public int m_IntVariable;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
[Serializable]
public struct ToClientPacket
{
    [MarshalAs(UnmanagedType.Bool)]
    public bool m_BoolVariable;
    public int m_IntVariable;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
    public int[] m_IntArray;
    public float m_FloatlVariable;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string m_StringlVariable;
}
728x90
반응형