블럭, 논블럭, 동기, 비동기

사설, 공인 아이피 구하기

using System.Net.Sockets; //for AddressFamily 

public static string GetInternalIPAddress()
{
    var host = Dns.GetHostEntry(Dns.GetHostName());
    foreach (var ip in host.AddressList)
    {
	if (ip.AddressFamily == AddressFamily.InterNetwork)
	{
	    return ip.ToString();
	}
    }
    throw new Exception("No network adapters with an IPv4 address in the system!");
}
public static string GetExternalIPAddress()
{
    string externalip = new WebClient().DownloadString("http://ipinfo.io/ip").Trim(); //http://icanhazip.com
    if (String.IsNullOrWhiteSpace(externalip))
    {
	externalip = GetInternalIPAddress();//null경우 Get Internal IP를 가져오게 한다.
    }
    return externalip;
}

TCP Server, TCP Client

통신포트

  • 참고링크
  • 0 사용하지 않음
  • 1~1023 잘 알려진 포트 (wall-known port)
  • 1024~49151 등록된 포트 (Registered port)
  • 49152 ~ 65535 동적 포트 (Dynamic port)
  • 그래서 권장포트는 49152 ~ 65535

전송 패키지 사이즈

  • TCP헤더와 IP 헤더를 제외하면 1460byte
  • 편의상 1024byte가 사용하기 적당함
    • 유니티와 유니티, 또는 C#과의 통신, 또는 C++와의 통신
    • 클래스 : Socket
    • 개체 직렬화 : Marshal
    • 전송 패킷 : 구조체 ↔ 바이트 배열

에코서버 형태로 변경, 쓰레드가 적용된 최종본

Server

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

public class SocketServer : MonoBehaviour {

   private Socket m_Server, m_Client;
   public int m_Port = 50001;
   public ToClientPacket m_SendPacket = new ToClientPacket();
   public ToServerPacket m_ReceivePacket = new ToServerPacket();
   private EndPoint m_RemoteEndPoint;
   private Thread t;
   void Start()
   {
       ThreadStart th = new ThreadStart(InitServer); //1.InitServer메소드를 위임. 
       t = new Thread(th);                     //2.쓰레드생성.
       t.Start();                              //3.시작 
       //InitServer();
   }
   void Update()
   {
       Receive();
       Send();
   }
   void OnApplicationQuit()
   {
       Debug.Log("Application ending after " + Time.time + " seconds");
       t.Abort(); //강제종료
       CloseServer();
   }
   void InitServer()
   {
       // SendPacket에 배열이 있으면 선언 해 주어야 함.
       m_SendPacket.m_IntArray = new int[2];
       m_Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
       m_RemoteEndPoint = new IPEndPoint(IPAddress.Any, m_Port);
       m_Server.Bind(m_RemoteEndPoint);
       m_Server.Listen(10); // client 접속을 기다림.
       m_Client = m_Server.Accept(); // client가 하나만 사용.
       SetSendPacket();
   }
   void Receive()
   {
       int receive = 0;
       byte[] packet = new byte[1024];
       try
       {
           receive = m_Client.Receive(packet);
           //receive = m_Server.Receive(packet);
       }
       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 
       SetSendPacketFromReceive();
   }
   void SetSendPacketFromReceive()
   {
       m_SendPacket.m_BoolVariable = m_ReceivePacket.m_BoolVariable;
       m_SendPacket.m_IntVariable = m_ReceivePacket.m_IntVariable;
       m_SendPacket.m_IntArray[0] = m_ReceivePacket.m_IntArray[0];
       m_SendPacket.m_IntArray[1] = m_ReceivePacket.m_IntArray[1];
       m_SendPacket.m_FloatlVariable = m_ReceivePacket.m_FloatlVariable;
       m_SendPacket.m_StringlVariable = m_ReceivePacket.m_StringlVariable;
   }
   void Send()
   {
       try
       {
           //SetSendPacket();
           byte[] sendPacket = StructToByteArray(m_SendPacket);
           m_Client.Send(sendPacket, 0, sendPacket.Length, SocketFlags.None);
           //m_Server.Send(sendPacket, 0, sendPacket.Length, SocketFlags.None);
       }
       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_Client != null)
       {
           m_Client.Close();
           m_Client = null;
       }
       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;
   }
}

Client

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

public class SocketClient : MonoBehaviour {

   private Socket m_Client;
   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();
       SetSendPacket();
   }

   void Update()
   {
       Receive();
       Send();
   }
   void OnApplicationQuit()
   {
       CloseClient();
   }
   void InitClient()
   {
       Debug.Log("client init");
       // SendPacket에 배열이 있으면 선언 해 주어야 함.
       m_SendPacket.m_IntArray = new int[2];
       m_ServerIpEndPoint = new IPEndPoint(IPAddress.Parse(m_Ip), m_Port);
       m_Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
       m_Client.Connect(m_ServerIpEndPoint);
   }
   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()
   {
       Debug.Log("client send");
       try
       {
           //SetSendPacket();
           byte[] sendPacket = StructToByteArray(m_SendPacket);
           m_Client.Send(sendPacket, 0, sendPacket.Length, SocketFlags.None);
       }
       catch (Exception ex)
       {
           Debug.Log(ex.ToString());
           return;
       }
   }
   void Receive()
   {
       Debug.Log("client receive");
       int receive = 0;
       Debug.Log("m_Client.Available:" + m_Client.Available);
       //Socket.Available = 네트워크에서 받아서 읽을 수 있는 데이터의 양.
       if (m_Client.Available != 0)
       {
           byte[] packet = new byte[1024];
           try
           {
               receive = m_Client.Receive(packet);
           }
           catch (Exception ex)
           {
               Debug.Log(ex.ToString());
               return;
           }
           m_ReceivePacket = ByteArrayToStruct<ToClientPacket>(packet);
           Debug.Log("receive length:" + receive);
           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 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;
   }
}

Packet

using System; 
using System.Runtime.InteropServices;

[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;
}


[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;
}

단일 접속에만 해당하여 더 개선이 필요합니다


error 에러

  • SocketException: 대상 컴퓨터에서 연결을 거부했으므로 연결하지 못했습니다. //서버가 실행되어 있지 않아서 일어나는 문제
  • m_Client = m_Server.Accept(); // client가 하나만 사용.
    • 상황에서 무한대기(유니티가 진행되지 않음)

업그레이드

  • 기존 방식은 update내에서 호출이 빈번하여 문제가 많이 발생할 수 있음
  • 패킷 수신 후 패킷이 존재할때만 발송할수 있도록 변경예정
  • 다중 클라이언트 접속 추가예정

using System;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Threading;
using System.Text;
using System.Collections;
using System.Collections.Generic;

public class GunaServer : MonoBehaviour
{
    private Socket m_server, m_client;
    private static List<Socket> r_clients = new List<Socket>();
    public List<string> ips = new List<string>();
    public int m_port = 50001;
    public static GunaPacket m_packet = new GunaPacket();
    private EndPoint m_endpoint;
    private Thread m_gate;
    public static ManualResetEvent allDone = new ManualResetEvent(false);
    void Start()
    {
        m_port = ServerUiManager.server_port;
        ThreadStart ins_th = new ThreadStart(initServer);
        m_gate = new Thread(ins_th);
        m_gate.Start();
    }

    void OnApplicationQuit()
    {
        //Debug.Log("application end");
        closeServer();
        if (m_gate != null) m_gate.Abort();
    }

    void initServer()
    {
        //Debug.Log("server init start");
        m_server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        m_endpoint = new IPEndPoint(IPAddress.Any, m_port);
        try
        {
            m_server.Bind(m_endpoint);
            m_server.Listen(10); // client 접속을 기다림.
            //Debug.Log("server stared");
            while (true)
            {
                allDone.Reset();
                //Debug.Log("Guna wait client...");
                m_server.BeginAccept(new AsyncCallback(acceptCallback), m_server);
                allDone.WaitOne();
            }
        }
        catch(Exception e)
        {
            Debug.Log(e.ToString());
            return;
        }
    }

    private static void broadcast()
    {
        foreach(Socket element in r_clients)
        {
            Send(element);
        }
    }

    private static void Send(Socket handler)
    {
        //Debug.Log("send progress");
        try {        
        byte[] sendPacket = StructToByteArray(m_packet);

        // Begin sending the data to the remote device.  
        handler.BeginSend(sendPacket, 0, sendPacket.Length, 0, new AsyncCallback(SendCallback), handler);
        // m_client.BeginSend(sendPacket, 0, sendPacket.Length, 0, new AsyncCallback(SendCallback), m_client); //클라이언트쪽 내용 (참고자료)
        }
        catch (Exception ex)
        {
            Debug.Log(ex.ToString());
            return;
        }
    }

    void acceptCallback(IAsyncResult ar) 
    {
        //Debug.Log("client accept!!!");
        allDone.Set();
        try
        {
            Socket listener = (Socket)ar.AsyncState;
            Socket handler = listener.EndAccept(ar);
            r_clients.Add(handler);
            string ip = ((IPEndPoint)(handler.RemoteEndPoint)).Address.ToString();
            //Debug.Log("client accept: " + ip);
            //Debug.Log("total_clients:" + r_clients.Count);
            ips.Add(ip);
            GunaStateObject state = new GunaStateObject();
            state.workSocket = handler;
            handler.BeginReceive(state.buffer, 0, GunaStateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
        }
        catch (Exception e)
        {
            Debug.Log(e.ToString());
            return;
        }
    }

    private static void SendCallback(IAsyncResult ar)
    {
        //Debug.Log("send progress : each client");
        try
        {
            // Retrieve the socket from the state object.  
            Socket handler = (Socket)ar.AsyncState;

            // Complete sending the data to the remote device.  
            int bytesSent = handler.EndSend(ar);
            //Console.WriteLine("Sent {0} bytes to client.", bytesSent);

            //handler.Shutdown(SocketShutdown.Both);
            //handler.Close();
        }
        catch (Exception e)
        {
            Debug.Log(e.ToString());
        }
    }

    public static void ReceiveCallback(IAsyncResult ar)
    {
        //Debug.Log("data received");
        GunaStateObject state = (GunaStateObject)ar.AsyncState;
        Socket handler = state.workSocket;
        //int bytesRend = handler.EndReceive(ar); //read data from the client socket
        int receive = 0;

        try
        {
            //receive = handler.Receive(state.buffer);
            receive = handler.EndReceive(ar);
        }
        catch (Exception ex)
        {
            Debug.Log(ex.ToString());
            Debug.Log("exception appeared");
            return;
        }
        m_packet = ByteArrayToStruct<GunaPacket>(state.buffer);
        showPacket();
        broadcast(); //받자마자 바로 브로드케스트 해보자
        //Debug.Log("receive length:" + receive);
        handler.BeginReceive(state.buffer, 0, GunaStateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); //이것으로 다회차 리시브가 될것인가
    }

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

    void closeServer()
    {
        if(m_server != null)m_server.Close();
        //Debug.Log("server closed");
    }

    static 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;
    }

    static 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;
    }
}


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

public class GunaClient : MonoBehaviour
{
    private Socket m_client;
    public string m_ip = "127.0.0.1";
    public int m_port = 50001;
    public GunaPacket m_packet = new GunaPacket();
    private IPEndPoint m_server_endpoint;
    private EndPoint m_client_endpoint;

    private static ManualResetEvent connectDone = new ManualResetEvent(false);
    private static ManualResetEvent sendDone = new ManualResetEvent(false);
    private static ManualResetEvent receiveDone = new ManualResetEvent(false);

    private Thread m_gate;

    void Start()
    {
        m_ip = ServerUiManager.server_ip;
        m_port = ServerUiManager.server_port;
        ThreadStart ins_th = new ThreadStart(initClient);
        m_gate = new Thread(ins_th);
        m_gate.Start();
        //initClient();
    }

    void initClient()
    {
        //Debug.Log("client init");
        m_server_endpoint = new IPEndPoint(IPAddress.Parse(m_ip), m_port);
        m_client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        m_client.BeginConnect(m_server_endpoint, new AsyncCallback(ConnectCallback), m_client);
        connectDone.WaitOne();

        //m_client.Shutdown(SocketShutdown.Both);
        //m_client.Close();
    }

    void ConnectCallback(IAsyncResult ar)
    {
        try
        {
            Socket client = (Socket)ar.AsyncState;
            client.EndConnect(ar);
            //Debug.Log("■ Socket connected to: " + client.RemoteEndPoint.ToString());
            Send();
            sendDone.WaitOne();
            //입장하자마자 센딩 해보자

            Receive(client);
            //receiveDone.WaitOne();

            connectDone.Set();
        }
        catch (Exception e)
        {
            Debug.Log(e.ToString());
        }
    }

    private void Receive(Socket client)
    {
        try
        {
            // Create the state object.  
            GunaStateObject state = new GunaStateObject();
            state.workSocket = client;

            // Begin receiving the data from the remote device.  
            client.BeginReceive(state.buffer, 0, GunaStateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
            //handler.BeginReceive(state.buffer, 0, GunaStateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); //서버쪽 리시버 (참고용)
        }
        catch (Exception e)
        {
            Debug.Log(e.ToString());
        }
    }

    private void ReceiveCallback(IAsyncResult ar)
    {
        //Debug.Log("client: received !!");
        try
        {
            // Retrieve the state object and the client socket
            // from the asynchronous state object.  
            GunaStateObject state = (GunaStateObject)ar.AsyncState;
            Socket client = state.workSocket;

            int receive = 0;
            // Read data from the remote device.
            //Debug.Log("client.Available:" + client.Available);
            //client.Available 네트워크에서 받아서 읽을수 있는 데이터의 양
            
            try
            {
                receive = client.EndReceive(ar);
            }
            catch (Exception ex)
            {
                Debug.Log(ex.ToString());
                return;
            }
            if (receive > 0)
            {
                //Debug.Log("■ client: packet received");
                //m_packet = ByteArrayToStruct<GunaPacket>(state.buffer);
                m_packet = ByteArrayToStruct<GunaPacket>(state.buffer);
                showPacket();
                //Debug.Log("receive length:" + receive);
                // 받은 값 처리
                client.BeginReceive(state.buffer, 0, GunaStateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); //이것으로 다회차 리시브가 될것인가
            }
            //receiveDone.Set(); //이게 문제인거 같다 셋을 안해주면 시스템이 락걸리넹
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }


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

    void OnApplicationQuit()
    {
        closeClient();
        if (m_gate != null) m_gate.Abort();
    }

    void closeClient()
    {
        if(m_client != null)
        {
            m_client.Close();
            m_client = null;
        }
    }

    public void Send()
    {
        //Debug.Log("client send");
        try
        {
            //SetSendPacket();

            byte[] sendPacket = StructToByteArray(m_packet);
            //m_client.Send(sendPacket, 0, sendPacket.Length, SocketFlags.None);
            m_client.BeginSend(sendPacket, 0, sendPacket.Length, 0, new AsyncCallback(SendCallback), m_client);
        }

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

    void SendCallback(IAsyncResult ar)
    {
        try
        {
            // Retrieve the socket from the state object.  
            Socket client = (Socket)ar.AsyncState;

            // Complete sending the data to the remote device.  
            int bytesSent = client.EndSend(ar);

            // Signal that all bytes have been sent.  
            sendDone.Set();
        }
        catch (Exception e)
        {
            Debug.Log(e.ToString());
        }
    }

    void SetSendPacket()
    {
        /*
        m_packet.m_BoolVariable = true;
        m_packet.m_IntVariable = 13;
        m_packet.m_IntArray = new int[2];
        m_packet.m_IntArray[0] = 7;
        m_packet.m_IntArray[1] = 47;
        m_packet.m_FloatlVariable = 2020;
        m_packet.m_StringlVariable = "Coder Zero";
        */
    }

    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;
    }
}


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

public class GunaStateObject
{
    // Size of receive buffer.  
    public const int BufferSize = 1024;

    // Receive buffer.  
    public byte[] buffer = new byte[BufferSize];

    // Received data string.
    public StringBuilder sb = new StringBuilder();

    // Client socket.
    public Socket workSocket = null;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
[Serializable]
public struct GunaPacket
{
    public const int VIDEO_STOP = 0;
    public const int VIDEO_PLAY = 1;
    public const int VIDEO_PAUSE = 2;
    /*
    [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;
    */
    public int m_VideoState;
    public double m_VideoSeeks;
    public int m_MideaReference_index;
    public int m_animation_index;
}


using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;

public class ServerUiManager : MonoBehaviour
{
    public static string server_ip = "127.0.0.1";
    public static int server_port = 50002;
    public Text global_ip_text;
    public Text local_ip_text;
    public InputField server_ip_input;
    public InputField server_port_input;
    void Awake()
    {
        global_ip_text.text = "global ip : " + GetExternalIPAddress();
        local_ip_text.text = "local ip : " + GetLocalIPAddress();
        //Debug.Log("[global_ipv4:" + GetExternalIPAddress() + "]");
        //Debug.Log("[local_ipv4:" + GetLocalIPAddress() + "]");
        getPlayerPrefs();
    }

    private void getPlayerPrefs()
    {
        //Debug.Log("PlayerPrefs setting");
        if (PlayerPrefs.HasKey("server_ip"))
        {
            //Debug.Log("server_ip:" + PlayerPrefs.GetString("server_ip"));
            server_ip_input.text = PlayerPrefs.GetString("server_ip");
            server_ip = PlayerPrefs.GetString("server_ip");
        }
        if (PlayerPrefs.HasKey("server_port"))
        {
            //Debug.Log("server_port:" + PlayerPrefs.GetString("server_port"));
            server_port_input.text = PlayerPrefs.GetString("server_port");
            server_port = int.Parse(PlayerPrefs.GetString("server_port"));
        }
    }
    private void setPlayerPrefs()
    {
        PlayerPrefs.SetString("server_ip", server_ip_input.text);
        PlayerPrefs.SetString("server_port", server_port_input.text);
    }

    public void SaveIpPort()
    {
        /*
        Debug.Log(server_ip_input.text);
        Debug.Log(server_port_input.text);
        */
        setPlayerPrefs();
        getPlayerPrefs();
    }

    public string GetLocalIPAddress()
    {
        var host = Dns.GetHostEntry(Dns.GetHostName());
        foreach (var ip in host.AddressList)
        {
            if (ip.AddressFamily == AddressFamily.InterNetwork)
            {
                return ip.ToString();
            }
        }
        throw new System.Exception("No network adapters with an IPv4 address in the system!");
    }

    public string GetExternalIPAddress()
    {
        string externalip = new WebClient().DownloadString("http://ipinfo.io/ip").Trim(); //http://icanhazip.com
        if (String.IsNullOrWhiteSpace(externalip))
        {
            //Debug.Log("global ip is null");
            externalip = GetLocalIPAddress();//null경우 Get Internal IP를 가져오게 한다.
        }
        return externalip;
    }
}


OnGUI로 개선한 버전

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;

public class ServerUiManager : MonoBehaviour
{
    public static string server_ip = "127.0.0.1";
    public static int server_port = 50002;
    public static string port_str = server_port.ToString();

    private string global_ip;
    private string local_ip;
    const int font_size = 30;
    private void OnGUI()
    {
        GUIStyle LabelStyle = new GUIStyle(GUI.skin.label);
        LabelStyle.fontSize = font_size;
        GUIStyle TextFieldStyle = new GUIStyle(GUI.skin.textField);
        TextFieldStyle.fontSize = font_size;
        GUIStyle ButtonStyle = new GUIStyle(GUI.skin.button);
        //ButtonStyle.alignment = TextAnchor.MiddleRight;
        ButtonStyle.fontSize = font_size;

        GUILayout.Label("global ip : " + global_ip, LabelStyle);
        GUILayout.Label("local ip : " + local_ip, LabelStyle);
        if (GUILayout.Button("save ip, port", ButtonStyle)) setPlayerPrefs();
        server_ip = GUILayout.TextField(server_ip, TextFieldStyle);
        port_str = GUILayout.TextField(port_str, TextFieldStyle);
        server_port = int.Parse(port_str);
    }
    void Awake()
    {
        global_ip = GetExternalIPAddress();
        local_ip = GetLocalIPAddress();
        getPlayerPrefs();
    }

    private void getPlayerPrefs()
    {
        //Debug.Log("PlayerPrefs setting");
        if (PlayerPrefs.HasKey("server_ip"))
        {
            //Debug.Log("server_ip:" + PlayerPrefs.GetString("server_ip"));
            server_ip = PlayerPrefs.GetString("server_ip");
        }
        if (PlayerPrefs.HasKey("server_port"))
        {
            //Debug.Log("server_port:" + PlayerPrefs.GetString("server_port"));
            server_port = int.Parse(PlayerPrefs.GetString("server_port"));
        }
        port_str = server_port.ToString();
    }
    private void setPlayerPrefs()
    {
        PlayerPrefs.SetString("server_ip", server_ip.ToString());
        PlayerPrefs.SetString("server_port", server_port.ToString());
    }

    public void SaveIpPort()
    {
        /*
        Debug.Log(server_ip_input.text);
        Debug.Log(server_port_input.text);
        */
        setPlayerPrefs();
        getPlayerPrefs();
    }

    public string GetLocalIPAddress()
    {
        var host = Dns.GetHostEntry(Dns.GetHostName());
        foreach (var ip in host.AddressList)
        {
            if (ip.AddressFamily == AddressFamily.InterNetwork)
            {
                return ip.ToString();
            }
        }
        throw new System.Exception("No network adapters with an IPv4 address in the system!");
    }

    public string GetExternalIPAddress()
    {
        string externalip = new WebClient().DownloadString("http://ipinfo.io/ip").Trim(); //http://icanhazip.com
        if (String.IsNullOrWhiteSpace(externalip))
        {
            //Debug.Log("global ip is null");
            externalip = GetLocalIPAddress();//null경우 Get Internal IP를 가져오게 한다.
        }
        return externalip;
    }
}

에러 개선중

  • guna_client의 리시브 콜백 부분이 try,catch안에 있어서 두번다시 리시브 되지 않던문제
      client.BeginReceive(state.buffer, 0, GunaStateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
    
  • try catch 구문 밖으로 빼야합니다. 리시브 성공실패와 관계없이 다음 리시브를 기대려야 합니다.