void InGameListner()
    {
        int counter = 0;

        print("Start");
        while (true)
        {
            byte[] buf = new byte[1024];
            try {
                udpClient.ReceiveFrom(buf, ref targetEndPoint);
                if (buf.Length > 0)
                {
                    // CNM에서 현재 아이디와 일치하는 정보를 빼온다. 누락됬다면 몽땅 처리해버림.
                    ClientNetworkMessage cnm = MyTool.BytesToStruct <ClientNetworkMessage>(buf);
                    while (counter != cnm.first_id + 1) // 마지막(첫번째) 데이터와 일치할때까지
                    {
                        byte[] currentBuf;
                        if (cnm.first_id == counter)
                        {
                            ++counter;
                            currentBuf = cnm.first;
                        }
                        else if (cnm.first_id + 1 == counter)
                        {
                            currentBuf = cnm.second;
                            ++counter;
                        }
                        else if (cnm.first_id + 2 == counter)
                        {
                            ++counter;
                            currentBuf = cnm.third;
                        }
                        else
                        {
                            counter    = cnm.first_id + 1;
                            currentBuf = cnm.third;
                        }
                        lock (listenerLocker)
                        {
                            networkReceivedList.Enqueue(currentBuf);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                print("리스너 폭팔 : " + e.Message);
                refreshThread = true;
                break;
            }
        }
        print("Exit");
    }
    public void ChangeState(ClientNetworkState state)
    {
        switch (state)
        {
        case ClientNetworkState.EndGame:
            Cursor.visible = true;
            if (listnerThread != null)
            {
                listnerThread.Abort();
            }
            if (udpClient != null)
            {
                udpClient.Close();
            }
            SceneManager.LoadScene("EndGame");
            break;

        case ClientNetworkState.Destroy:
            OnApplicationQuit();
            SceneManager.LoadScene("Server");
            Destroy(this);
            break;

        case ClientNetworkState.InGame:
        {
            networkSendList.Clear();
            networkReceivedList.Clear();
            cnm          = new ClientNetworkMessage();
            cnm.first_id = 0;
            cnm.first    = cnm.second = cnm.third = null;

            if (SceneManager.GetActiveScene().name != "InGame")
            {
                SceneManager.LoadScene("InGame");
            }
            if (listnerThread != null)
            {
                listnerThread.Abort();
            }
            listnerThread = new Thread(new ThreadStart(InGameListner));
            listnerThread.Start();
        }
        break;

        case ClientNetworkState.Matching:
        {
            if (currentState == ClientNetworkState.Matching && udpClient != null)
            {
                try
                {
                    byte[] buf2 = new byte[1];
                    buf2[0] = (byte)CTSType.Disconnect;
                    udpClient.SendTo(buf2, targetEndPoint);
                }
                catch
                {
                    udpClient = null;
                    ChangeState(ClientNetworkState.Matching);
                    return;
                }
            }
            Cursor.visible = true;
            targetIp       = "";
            // 서버 아이피를 받음
            if (udpClient != null)
            {
                udpClient.Close();
            }
            if (listnerThread != null)
            {
                listnerThread.Abort();
            }
            if (SceneManager.GetActiveScene().name != "Matching")
            {
                SceneManager.LoadScene("Matching");
            }
            if (SceneManager.GetSceneByName("Matching").GetRootGameObjects().Length > 0)
            {
                var       objects       = SceneManager.GetSceneByName("Matching").GetRootGameObjects();
                Transform root_Matching = objects[0].transform;
                foreach (var myObject in objects)
                {
                    if (myObject.transform.name == "Canvas")
                    {
                        root_Matching = myObject.transform;
                    }
                }
                var mtext = root_Matching.transform.Find("MatchingText").GetComponent <UnityEngine.UI.Text>();
                if (mtext != null)
                {
                    mtext.text = "매칭 중!";
                }
                var mtext2 = root_Matching.transform.Find("Button").Find("MatchingButtonText").GetComponent <UnityEngine.UI.Text>();
                if (mtext2 != null)
                {
                    mtext2.text = "매칭 취소";
                }
            }

            StreamReader reader   = new StreamReader("server.txt");
            var          serverIp = reader.ReadLine();
            reader.Close();
            print(serverIp + "에 요청");

            // 서버에 매칭 요청을 함.
            IPEndPoint serverEndpoint_IP = new IPEndPoint(IPAddress.Parse(serverIp), CS_PORT);
            targetEndPoint = (EndPoint)serverEndpoint_IP;
            IPEndPoint Remote_IP      = new IPEndPoint(IPAddress.Any, 0);
            EndPoint   remoteEndpoint = (EndPoint)Remote_IP;
            udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            udpClient.ReceiveTimeout = 5000;
            udpClient.SendTimeout    = 5000;
            byte[] buf = new byte[1];
            buf[0] = (byte)CTSType.Matching;
            udpClient.SendTo(buf, targetEndPoint);
            byte[] data = new byte[1024];
            try
            {
                udpClient.ReceiveFrom(data, ref remoteEndpoint);
                if ((STCType)data[0] != STCType.Connected)
                {
                    SceneManager.LoadScene("Aleart");
                }
                else
                {
                    // 모든게 성공했다면 쓰레드에서 대기한다
                    listnerThread = new Thread(new ThreadStart(MatchingListner));
                    listnerThread.Start();
                }
            }
            catch (Exception e)
            {
                print(e);
                SceneManager.LoadScene("Aleart");
            }
        }
        break;

        case ClientNetworkState.Ready:
        {
            Cursor.visible = true;
            if (currentState == ClientNetworkState.Matching && udpClient != null)
            {
                byte[] buf = new byte[1];
                buf[0] = (byte)CTSType.Disconnect;
                udpClient.SendTo(buf, targetEndPoint);
            }
            if (listnerThread != null)
            {
                listnerThread.Abort();
            }
            if (udpClient != null)
            {
                udpClient.Close();
            }
            if (SceneManager.GetActiveScene().name != "Matching")
            {
                SceneManager.LoadScene("Matching");
            }

            if (SceneManager.GetSceneByName("Matching").GetRootGameObjects().Length > 0)
            {
                var       objects       = SceneManager.GetSceneByName("Matching").GetRootGameObjects();
                Transform root_Matching = objects[0].transform;
                foreach (var myObject in objects)
                {
                    if (myObject.transform.name == "Canvas")
                    {
                        root_Matching = myObject.transform;
                    }
                }
                var mtext = root_Matching.transform.Find("MatchingText").GetComponent <UnityEngine.UI.Text>();
                if (mtext != null)
                {
                    mtext.text = "매칭 시작을 눌러주세요.";
                }
                var mtext2 = root_Matching.transform.Find("Button").Find("MatchingButtonText").GetComponent <UnityEngine.UI.Text>();
                if (mtext2 != null)
                {
                    mtext2.text = "매칭 시작";
                }
            }
            break;
        }

        default:
            print("Unexpected State");
            break;
        }
        currentState = state;
        print("상태 전환 : " + currentState);
    }