void RequestLogin(string userID, string authToken)
        {
            DevLog.Write("서버에 로그인 요청", LOG_LEVEL.INFO);

            var reqLogin = new CSBaseLib.PKTReqLogin()
            {
                UserID = userID, AuthToken = authToken
            };

            var Body     = MessagePackSerializer.Serialize(reqLogin);
            var sendData = CSBaseLib.PacketToBytes.Make(CSBaseLib.PACKETID.REQ_LOGIN, Body);

            PostSendPacket(sendData);
        }
        // 방 입장
        private void Button_Click_3(object sender, RoutedEventArgs e)
        {
            var roomNum = textBoxRoomNum.Text.ToInt32();

            DevLog.Write("서버에 방 입장 요청", LOG_LEVEL.INFO);

            var request = new CSBaseLib.PKTReqRoomEnter()
            {
                RoomNumber = roomNum
            };

            var Body     = MessagePackSerializer.Serialize(request);
            var sendData = CSBaseLib.PacketToBytes.Make(CSBaseLib.PACKETID.REQ_ROOM_ENTER, Body);

            PostSendPacket(sendData);
        }
        void NetworkReadProcess()
        {
            const Int16 PacketHeaderSize = CSBaseLib.PacketDef.PACKET_HEADER_SIZE;

            while (IsNetworkThreadRunning)
            {
                if (Network.IsConnected() == false)
                {
                    System.Threading.Thread.Sleep(1);
                    continue;
                }

                var recvData = Network.Receive();

                if (recvData != null)
                {
                    PacketBuffer.Write(recvData.Item2, 0, recvData.Item1);

                    while (true)
                    {
                        var data = PacketBuffer.Read();
                        if (data.Count < 1)
                        {
                            break;
                        }

                        var packet = new PacketData();
                        packet.DataSize = (short)(data.Count - PacketHeaderSize);
                        packet.PacketID = BitConverter.ToInt16(data.Array, data.Offset + 2);
                        packet.Type     = (SByte)data.Array[(data.Offset + 4)];
                        packet.BodyData = new byte[packet.DataSize];
                        Buffer.BlockCopy(data.Array, (data.Offset + PacketHeaderSize), packet.BodyData, 0, (data.Count - PacketHeaderSize));
                        lock (((System.Collections.ICollection)RecvPacketQueue).SyncRoot)
                        {
                            RecvPacketQueue.Enqueue(packet);
                        }
                    }
                    //DevLog.Write($"받은 데이터: {recvData.Item2}", LOG_LEVEL.INFO);
                }
                else
                {
                    Network.Close();
                    SetDisconnectd();
                    DevLog.Write("서버와 접속 종료 !!!", LOG_LEVEL.INFO);
                }
            }
        }
        // 접속하기
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            string address = textBoxIP.Text;

            if (checkBoxLocalHostIP.IsChecked == true)
            {
                address = "127.0.0.1";
            }

            int port = Convert.ToInt32(textBoxPort.Text);

            DevLog.Write($"서버에 접속 시도: ip:{address}, port:{port}", LOG_LEVEL.INFO);

            if (Network.Connect(address, port))
            {
                labelConnState.Content = string.Format("{0}. 서버에 접속 중", DateTime.Now);
                ClientState            = CLIENT_STATE.CONNECTED;
            }
            else
            {
                labelConnState.Content = string.Format("{0}. 서버에 접속 실패", DateTime.Now);
            }
        }
        void PacketProcess(PacketData packet)
        {
            switch ((PACKETID)packet.PacketID)
            {
            case PACKETID.REQ_RES_TEST_ECHO:
            {
                DevLog.Write($"Echo 응답: {packet.BodyData.Length}", LOG_LEVEL.INFO);
                break;
            }

            case PACKETID.RES_LOGIN:
            {
                var resData = MessagePackSerializer.Deserialize <PKTResLogin>(packet.BodyData);

                if (resData.Result == (short)ERROR_CODE.NONE)
                {
                    ClientState = CLIENT_STATE.LOGIN;
                    DevLog.Write("로그인 성공", LOG_LEVEL.INFO);
                }
                else
                {
                    DevLog.Write(string.Format("로그인 실패: {0} {1}", resData.Result, ((ERROR_CODE)resData.Result).ToString()), LOG_LEVEL.ERROR);
                }
            }
            break;

            case PACKETID.RES_ROOM_ENTER:
            {
                var resData = MessagePackSerializer.Deserialize <PKTResRoomEnter>(packet.BodyData);

                if (resData.Result == (short)ERROR_CODE.NONE)
                {
                    ClientState = CLIENT_STATE.ROOM;
                    DevLog.Write("방 입장 성공", LOG_LEVEL.INFO);
                }
                else
                {
                    DevLog.Write(string.Format("방입장 실패: {0} {1}", resData.Result, ((ERROR_CODE)resData.Result).ToString()), LOG_LEVEL.INFO);
                }
            }
            break;

            case PACKETID.NTF_ROOM_USER_LIST:
            {
                var ntfData = MessagePackSerializer.Deserialize <PKTNtfRoomUserList>(packet.BodyData);

                foreach (var user in ntfData.UserIDList)
                {
                    listBoxRoomUserList.Items.Add(user);
                }
            }
            break;

            case PACKETID.NTF_ROOM_NEW_USER:
            {
                var ntfData = MessagePackSerializer.Deserialize <PKTNtfRoomNewUser>(packet.BodyData);
                listBoxRoomUserList.Items.Add(ntfData.UserID);
            }
            break;

            case PACKETID.RES_ROOM_LEAVE:
            {
                var resData = MessagePackSerializer.Deserialize <PKTResRoomLeave>(packet.BodyData);

                if (resData.Result == (short)ERROR_CODE.NONE)
                {
                    listBoxRoomUserList.Items.Remove(textBoxID.Text);
                    ClientState = CLIENT_STATE.LOGIN;
                    DevLog.Write("방 나가기 성공", LOG_LEVEL.INFO);
                }
                else
                {
                    DevLog.Write(string.Format("방 나가기 실패: {0} {1}", resData.Result, ((ERROR_CODE)resData.Result).ToString()), LOG_LEVEL.ERROR);
                }
            }
            break;

            case PACKETID.NTF_ROOM_LEAVE_USER:
            {
                var ntfData = MessagePackSerializer.Deserialize <PKTNtfRoomLeaveUser>(packet.BodyData);
                listBoxRoomUserList.Items.Remove(ntfData.UserID);
            }
            break;

            case PACKETID.NTF_ROOM_CHAT:
            {
                textBoxSendChat.Text = "";

                var ntfData = MessagePackSerializer.Deserialize <PKTNtfRoomChat>(packet.BodyData);
                listBoxChat.Items.Add($"[{ntfData.UserID}]: {ntfData.ChatMessage}");
            }
            break;
            }
        }