コード例 #1
0
        private static void RoomListRefresh(CustomProtocolManager.Header header, byte[] msg)
        {
            ClientInfo            ci        = ClientInfo.getInstance();
            List <RoomCreateData> roomDatas = CustomProtocolManager.ParseRoomListPacket(msg, 0, msg.Length);

            ci.mainClientFrame.RoomListRefresh(roomDatas);
        }
コード例 #2
0
        private static void SendRoomList(CustomProtocolManager.Header header, byte[] msg, User target)
        {
            if (target.ChannelNumber == -1)
            {
                return;
            }

            List <RoomCreateData> list = new List <RoomCreateData>();
            Channel c = ServerProperty.getInstance().channelsList[target.ChannelNumber];

            RoomCreateData rcd;

            foreach (KeyValuePair <string, Room> data in c.rooms)
            {
                rcd = new RoomCreateData()
                {
                    gameInfo       = data.Value.gameInfo,
                    gameParameters = data.Value.gameParameters,
                    roomName       = data.Value.roomName,
                    HostNickName   = data.Value.HostNickName,
                    teamCount      = data.Value.teamCount,
                    maxCapacity    = data.Value.maxCapacity,
                    password       = data.Value.password
                };

                list.Add(rcd);
            }

            SendToUser(target, CustomProtocolManager.MakeRoomListPacket(list));
        }
コード例 #3
0
        private static void ServerMessageHandleFunction(byte[] msg)
        {
            Thread msgThread = new Thread(() => new MessageForm(CustomProtocolManager.ParseServerMessagePacket(msg, 0, msg.Length)).ShowDialog());

            msgThread.IsBackground = false;
            msgThread.Start();
        }
コード例 #4
0
 private void RoomListRefresh()
 {
     if (!inChannel)
     {
         return;
     }
     MessageHandler.SendToServer(CustomProtocolManager.MakeRoomListRequestPacket());
 }
コード例 #5
0
 public void RequestJoinRoom()
 {
     PackedData.RoomCreateData roomData;
     try
     {
         roomData = (PackedData.RoomCreateData)list_GameListView.Items[list_GameListView.SelectedIndex];
         MessageHandler.SendToServer(CustomProtocolManager.MakeRoomEnterPacket(roomData.HostNickName));
     }
     catch (Exception e) { }
 }
コード例 #6
0
        private static void UserListRefresh(CustomProtocolManager.Header header, byte[] msg)
        {
            ClientInfo    ci = ClientInfo.getInstance();
            List <string> list;
            bool          isRoom;

            isRoom = CustomProtocolManager.ParseUserList(msg, 0, (int)header.size, out list);

            ci.mainClientFrame.UserListRefresh(isRoom, list);
        }
コード例 #7
0
        private void RequestCreateRoom()
        {
            RoomCreateForm rcf = new RoomCreateForm();

            if (rcf.ShowDialog() == DialogResult.OK)
            {
                MessageHandler.SendToServer(CustomProtocolManager.MakeRoomCreatePacket(rcf.data));
            }

            rcf.Dispose();
        }
コード例 #8
0
        // 채널에 입장하겠다고 서버에 알리고 결과를 받아 처리한다.
        private void EnterChannel()
        {
            ChannelListItem info = (ChannelListItem)list_ChannelList.SelectedItem;

            if (info == null)
            {
                return;
            }

            MessageHandler.SendToServer(CustomProtocolManager.MakeChannelEnterRequestPacket(info.index));
        }
コード例 #9
0
        private static void RoomChangeHandle(CustomProtocolManager.Header header, byte[] msg)
        {
            RoomCreateData roomData = CustomProtocolManager.ParseRoomResponsePacket(msg, 0, msg.Length);

            if (roomData == null) // 빠져나오는 반응이거나 실패의 의미
            {
                ClientInfo.getInstance().mainClientFrame.ExitingRoomUIChanger();
                return;
            }

            ClientInfo.getInstance().mainClientFrame.EnteringRoom(roomData);
        }
コード例 #10
0
        private static void RoomStateChangeHandle(CustomProtocolManager.Header header, byte[] msg, User target)
        {
            string arg;

            string[]       tmp;
            ServerProperty sp = ServerProperty.getInstance();
            Room           targetRoom;
            User           user;

            try
            {
                targetRoom = sp.channelsList[target.ChannelNumber].rooms[target.RoomID];
            }
            catch { return; }

            switch (CustomProtocolManager.ParseRoomStateChangePacket(msg, 0, msg.Length, out arg))
            {
            case CustomProtocolManager.RoomStateChangeOption.Start:
                try
                {
                    if (!target.RoomID.Equals(target.Nickname))
                    {
                        return;                                             // 방장이 아니면 거부
                    }
                    else if (targetRoom.members.Count < 2)
                    {
                        return;                                        // 최소 실행 인원이 안되면 거부
                    }
                    foreach (KeyValuePair <string, RoomMember> r in targetRoom.members)
                    {
                        user = sp.channelsList[target.ChannelNumber].users[r.Value.Nickname];

                        // 방장의 경우
                        if (r.Key.Equals(target.Nickname))
                        {
                            arg = String.Format("NormalStart {0} {1} {2} {3}", "SERVER", targetRoom.members.Count - 1, r.Value.Nickname, r.Value.TeamNumber);
                        }
                        else      // 그 외의 경우
                        {
                            tmp = ("" + target.client.Client.RemoteEndPoint).Split(':');
                            arg = String.Format("NormalStart {0} {1} {2} {3}", "CLIENT",
                                                tmp[0], r.Value.Nickname, r.Value.TeamNumber);
                        }
                        SendToUser(user, CustomProtocolManager.MakeRoomStateChangePacket(CustomProtocolManager.RoomStateChangeOption.Start, arg));
                    }
                }
                catch { }
                break;

            default: break;
            }
        }
コード例 #11
0
        private static void ChannelInfoMsgHandleFunction(CustomProtocolManager.Header header, byte[] msg)
        {
            ClientInfo  ci = ClientInfo.getInstance();
            ChannelInfo info;


            if (ci.channelSelect == null)
            {
                return;                           // 채널 선택창이 없으면 메세지의 의미가 없으므로 중단
            }
            int index = CustomProtocolManager.ParseChannelInfoPacket(msg, 0, (int)header.size, out info);

            ci.channelSelect.AddChannelList(info, index);
        }
コード例 #12
0
        // 채널 정보를 보냅니다.
        private static void SendChannelInfo(byte[] msg, ref User target)
        {
            ServerProperty ci = ServerProperty.getInstance();

            byte[] packet;

            Channel c;

            for (int i = 0; i < ci.channelsList.Count; ++i)
            {
                c      = ci.channelsList[i];
                packet = CustomProtocolManager.MakeChannelInfoPacket(c.MakeInfo(), i);
                SendToUser(target, packet);
            }
        }
コード例 #13
0
        // 서버명 요청 및 클라이언트 프로그램 인증 패킷 처리.
        private static void MakeConnectionMsgHandleFunction(CustomProtocolManager.Header header, byte[] msg, ref User target)
        {// 서버로 들어오는 MakeConnection 계 메세지는 000밖에 없다.
            ServerProperty sp = ServerProperty.getInstance();

            // 0번 옵션이 아니거나 올바른 서버명 요청패킷이 아니라면 메세지는 처분한다.
            if (header.optNumber != 0 || !CustomProtocolManager.ParseConnectRequestPacket(msg, 0))
            {
                return;
            }

            target.Id = CustomProtocolManager.AUTHORIZED_CLIENT_TEMP_NAME;
            byte[] packet = CustomProtocolManager.MakeClientReqInfoPacket(sp.serverName, sp.RSAparams, sp.gameInfoList);

            SendToUser(target, packet);
        }
コード例 #14
0
        // 회원가입 처리
        private static void AccountMakingHandler(byte[] msg, User client)
        {
            JoinData data = CustomProtocolManager.ParseJoinPacket(msg, 0, msg.Length);

            CustomProtocolManager.GenericResponseType response;

            if (ConDatabase.AccountMakeFunction(CustomProtocolManager.ParseJoinPacket(msg, 0, msg.Length)))
            {
                response = CustomProtocolManager.GenericResponseType.Acknowledge;
            }
            else
            {
                response = CustomProtocolManager.GenericResponseType.Denied;
            }

            SendToUser(client, CustomProtocolManager.MakeAuthTypeResponsePacket(response));
        }
コード例 #15
0
        public void Dispose()
        {
            ServerProperty sp = ServerProperty.getInstance();

            if (client != null)
            {
                client.Close();
            }

            if (ChannelNumber != -1)
            {
                User temp;
                PackedData.RoomMember temp2;

                sp.channelsList[ChannelNumber].users.TryRemove(Nickname, out temp);

                try
                {
                    if (RoomID == Nickname)
                    {
                        foreach (KeyValuePair <string, PackedData.RoomMember> u in sp.channelsList[ChannelNumber].rooms[RoomID].members)
                        {
                            MessageHandler.SendToUser(
                                sp.channelsList[ChannelNumber].users[u.Value.Nickname],
                                CustomProtocolManager.MakeRoomResponsePacket()
                                );
                        }
                        Room dummy;
                        sp.channelsList[ChannelNumber].rooms.TryRemove(RoomID, out dummy);
                    }
                    else if (RoomID != null)
                    {
                        sp.channelsList[ChannelNumber].rooms[RoomID].members.TryRemove(Nickname, out temp2);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine("user.Dispose: " + e.Message);
                }
            }


            Id       = null;
            Nickname = null;
        }
コード例 #16
0
        /*
         * opt 0 - 내용; 채널에 채팅
         * opt 1 - 내용; 게임방에 채팅
         * TODO: opt 2 - 팀번호 + 내용; 팀 채팅
         * TODO: opt 3 - 길이 + 유저명 + 길이 + 내용; 대상 유저에게 귓속말
         */

        private static void ChattingHandleFunction(CustomProtocolManager.Header header, byte[] msg, ref User target)
        {
            ServerProperty sp = ServerProperty.getInstance();

            byte[] packet;

            string chat = target.Nickname + ": " + CustomProtocolManager.ParseGeneralChatting(msg, 0, msg.Length);



            switch ((CustomProtocolManager.ChattingOption)header.optNumber)
            {
            case CustomProtocolManager.ChattingOption.Channel:
                packet = CustomProtocolManager.MakeGeneralChatting(chat, CustomProtocolManager.NormalChatType.Channel);
                foreach (KeyValuePair <string, User> pair in sp.channelsList[target.ChannelNumber].users)
                {
                    SendToUser(pair.Value, packet);
                }
                break;

            case CustomProtocolManager.ChattingOption.Room:
                if (target.RoomID == null)
                {
                    return;
                }
                packet = CustomProtocolManager.MakeGeneralChatting(chat, CustomProtocolManager.NormalChatType.Room);
                foreach (KeyValuePair <string, RoomMember> pair in sp.channelsList[target.ChannelNumber].rooms[target.RoomID].members)
                {
                    SendToUser(sp.channelsList[target.ChannelNumber].users[pair.Value.Nickname], packet);
                }
                break;

            /* 테스트버전 미사용
             * case CustomProtocolManager.ChattingOption.Team:
             *
             * break;
             *
             * case CustomProtocolManager.ChattingOption.Whisper:
             * break;
             */
            default: break;
            }
        }
コード例 #17
0
        private static void RoomCreateHandle(CustomProtocolManager.Header header, byte[] msg, User target)
        {
            if (target.RoomID != null)
            {
                return;
            }
            target.RoomID = target.Nickname;

            RoomCreateData data = CustomProtocolManager.ParseRoomCreatePacket(msg, 0, msg.Length);
            ServerProperty sp   = ServerProperty.getInstance();

            data.HostNickName = target.Nickname;

            Room r = new Room(data);

            r.members.TryAdd(target.Nickname, new RoomMember(target.Nickname));
            sp.channelsList[target.ChannelNumber].rooms.TryAdd(target.Nickname, r);

            SendToUser(target, CustomProtocolManager.MakeRoomResponsePacket(true, data));
        }
コード例 #18
0
        private static void RoomStateChangeHandle(CustomProtocolManager.Header header, byte[] msg)
        {
            string     arg;
            ClientInfo ci = ClientInfo.getInstance();

            CustomProtocolManager.ParseRoomStateChangePacket(msg, 0, msg.Length, out arg);

            foreach (GameRegistry gr in ci.gameRegistries)
            {
                if (GameInfo.IsSameInfo(gr.gameInfo, ci.roomInfo.gameInfo))
                {
                    try
                    {
                        ci.gameProcess = Process.Start(gr.folderPath + @"\Game.exe ", arg);
                        MessageBox.Show(arg);
                    }
                    catch { throw new Exception("게임을 찾을수 없었습니다. 실행파일을 Game.exe로 이름을 변경해주십시오."); }
                }
            }
        }
コード例 #19
0
        private static void SendUserInfo(CustomProtocolManager.Header header, byte[] msg, User target)
        {
            List <string> userList = new List <string>();

            if (target.ChannelNumber != -1)
            {
                Channel channel = ServerProperty.getInstance().channelsList[target.ChannelNumber];
                foreach (string nickname in channel.users.Keys)
                {
                    userList.Add(nickname);
                }
                SendToUser(target, CustomProtocolManager.MakeUserList(userList, false));
            }

            if (target.RoomID != null)
            {
                Room room;
                userList.Clear();
                try
                {
                    room = ServerProperty.getInstance().channelsList[target.ChannelNumber].rooms[target.RoomID];
                }
                catch {
                    target.RoomID = null;
                    return;
                }

                foreach (KeyValuePair <string, RoomMember> pair in room.members)
                {
                    if (pair.Value.TeamNumber != 0)
                    {
                        userList.Add(pair.Key + "(" + pair.Value.TeamNumber + ")");
                    }
                    else
                    {
                        userList.Add(pair.Key);
                    }
                }
                SendToUser(target, CustomProtocolManager.MakeUserList(userList, true));
            }
        }
コード例 #20
0
        // 회원가입정보 중복여부 확인 처리
        private static void AccountDuplicateCheckHandler(byte[] msg, User client)
        {
            CustomProtocolManager.GenericResponseType response;
            string context;

            CustomProtocolManager.DuplicateCheckJoinType joinType;

            joinType = CustomProtocolManager.ParseDuplicateCheckForJoin(msg, 0, (uint)msg.Length, out context);

            if (ConDatabase.AccountDuplicateCheckFunction(joinType, context))
            {
                response = CustomProtocolManager.GenericResponseType.Acknowledge;
            }
            else
            {
                response = CustomProtocolManager.GenericResponseType.Denied;
            }

            byte[] packet = CustomProtocolManager.MakeAuthTypeResponsePacket(response);

            SendToUser(client, packet);
        }
コード例 #21
0
        /// <summary>
        /// 로그인을 시도하고 결과를 반환합니다.
        /// </summary>
        /// <param name="token">로그인에 사용할 토큰을 의미합니다.</param>
        /// <returns>로그인 결과를 의미합니다.</returns>
        public static bool TryLogin(CustomProtocolManager.LoginToken token)
        {
            ConnectInfo ci = ConnectInfo.getInstance();

            SendToServer(CustomProtocolManager.MakeLoginPacket(token, ci.securityParameter), true);
            int index          = 0;
            int requiredLength = CustomProtocolManager.HEADER_SIZE + 1;

            // 헤더 수신
            byte[] recvData = new byte[requiredLength];
            if (!ReceiveFunction(ci.tcpClient.Client, ref recvData, ref index, requiredLength))
            {
                return(false);
            }

            if (CustomProtocolManager.ParseResponsePacket(recvData, CustomProtocolManager.HEADER_SIZE)
                == CustomProtocolManager.GenericResponseType.Acknowledge)
            {
                return(true);
            }
            return(false);
        }
コード例 #22
0
        /// <summary>
        /// 계정을 만들어달라고 요청합니다. 성공 여부가 반환됩니다.
        /// </summary>
        /// <param name="data">계정 양식입니다.</param>
        /// <returns>성공 여부</returns>
        public static bool MakeAccount(JoinData data)
        {
            ConnectInfo ci = ConnectInfo.getInstance();

            SendToServer(CustomProtocolManager.MakeJoinPacket(data), true);
            int index          = 0;
            int requiredLength = CustomProtocolManager.HEADER_SIZE + 1;

            byte[] recvData = new byte[requiredLength];

            if (!ReceiveFunction(ci.tcpClient.Client, ref recvData, ref index, requiredLength))
            {
                return(false);
            }

            if (CustomProtocolManager.ParseResponsePacket(recvData, CustomProtocolManager.HEADER_SIZE)
                == CustomProtocolManager.GenericResponseType.Acknowledge)
            {
                return(true);
            }
            return(false);
        }
コード例 #23
0
        /// <summary>
        /// 회원가입시 데이터가 중복되었는지 개별적으로 확인할때 사용하는 함수입니다.
        /// 형식과 데이터를 받아서 중복 여부를 확인합니다. True일 경우 사용해도 좋다는 의미입니다.
        /// </summary>
        /// <param name="type">확인할 데이터의 타입입니다.</param>
        /// <param name="context">확인할 데이터의 내용입니다.</param>
        /// <returns>사용 가능 여부</returns>
        public static bool CheckDuplicateData(CustomProtocolManager.DuplicateCheckJoinType type, string context)
        {
            ConnectInfo ci = ConnectInfo.getInstance();

            SendToServer(CustomProtocolManager.MakeDuplicateCheckForJoin(type, context), true);
            int index          = 0;
            int requiredLength = CustomProtocolManager.HEADER_SIZE + 1;

            byte[] recvData = new byte[requiredLength];

            if (!ReceiveFunction(ci.tcpClient.Client, ref recvData, ref index, requiredLength))
            {
                return(false);
            }

            if (CustomProtocolManager.ParseResponsePacket(recvData, CustomProtocolManager.HEADER_SIZE)
                == CustomProtocolManager.GenericResponseType.Acknowledge)
            {
                return(true);
            }
            return(false);
        }
コード例 #24
0
        // 로그인 인증 진행 함수
        private static void LoginHandleFunction(byte[] msg, User target)
        {
            CustomProtocolManager.LoginToken loginInfo;
            string nickname;

            // 패킷 해석
            loginInfo = CustomProtocolManager.ParseLoginPacket(msg, 0, ServerProperty.getInstance().RSAparams);

            // 로그인 절차. 실패시 실패했다는 내용의 응답을 보내고 함수를 종료한다
            bool flag = ConDatabase.LoginFunction(loginInfo.id, loginInfo.password, out nickname);

            if (!flag || ServerProperty.getInstance().users.Exists((User u) => { return(u.Id == loginInfo.id); }))
            {
                SendToUser(target, CustomProtocolManager.MakeAuthTypeResponsePacket(CustomProtocolManager.GenericResponseType.Denied));
                return;
            }

            target.Id       = loginInfo.id;
            target.Nickname = nickname;

            // TODO: 성공시에는 User의 정보값을 갱신하고 성공했다는 응답을 보낸후 환영메세지를 보낸다.
            SendToUser(target, CustomProtocolManager.MakeAuthTypeResponsePacket(CustomProtocolManager.GenericResponseType.Acknowledge));
            SendToUser(target, CustomProtocolManager.MakeServerMessagePacket(ServerProperty.getInstance().welcomeMessage));
        }
コード例 #25
0
        private static void RoomEnterHandle(CustomProtocolManager.Header header, byte[] msg, User target)
        {
            ServerProperty sp             = ServerProperty.getInstance();
            string         targetRoomHost = CustomProtocolManager.ParseRoomEnterPacket(msg, 0, msg.Length);

            try
            {
                if (targetRoomHost.Equals("") || targetRoomHost == null)
                {
                    if (target.RoomID.Equals(target.Nickname))
                    {
                        string str = target.RoomID;

                        foreach (KeyValuePair <string, RoomMember> u in sp.channelsList[target.ChannelNumber].rooms[str].members)
                        {
                            sp.channelsList[target.ChannelNumber].users[u.Key].RoomID = null;
                            SendToUser(sp.channelsList[target.ChannelNumber].users[u.Key], CustomProtocolManager.MakeRoomResponsePacket());
                        }

                        Room rDummy;
                        sp.channelsList[target.ChannelNumber].rooms.TryRemove(str, out rDummy);
                        return;
                    }

                    RoomMember dummy;
                    sp.channelsList[target.ChannelNumber].rooms[target.RoomID].members.TryRemove(target.Nickname, out dummy);
                    target.RoomID = null;
                    SendToUser(target, CustomProtocolManager.MakeRoomResponsePacket());
                    return;
                }
            }
            catch { }


            if (target.RoomID != null)
            {
                return;
            }

            Room targetRoom;

            try
            {
                targetRoom = sp.channelsList[target.ChannelNumber].rooms[targetRoomHost];
            }
            catch { return; }

            if (targetRoom.members.Count < targetRoom.maxCapacity)
            {
                targetRoom.members.TryAdd(target.Nickname, new RoomMember(target.Nickname));
                target.RoomID = targetRoom.HostNickName;
                SendToUser(target, CustomProtocolManager.MakeRoomResponsePacket(true,
                                                                                new RoomCreateData()
                {
                    gameInfo       = targetRoom.gameInfo,
                    gameParameters = targetRoom.gameParameters,
                    roomName       = targetRoom.roomName,
                    HostNickName   = targetRoom.HostNickName,
                    teamCount      = targetRoom.teamCount,
                    maxCapacity    = targetRoom.maxCapacity,
                    password       = targetRoom.password
                })
                           );
            }
        }
コード例 #26
0
        /// <summary>
        /// 서버명을 요청한 후 수신받아 기록합니다. 절차는 동기식으로 작동합니다.
        /// 이 함수를 사용하면 인증 가능한 상태라고 초기화 되기 때문에,
        /// 처음 접속시가 아니면 사용하지 마십시오.
        /// </summary>
        /// <returns>성공 여부를 나타냅니다.</returns>
        public static bool ReceiveDefaultInfo()
        {
            string serverName;

            System.Security.Cryptography.RSAParameters parameters;
            int index = 0;

            byte[]          data;
            List <GameInfo> reqInfos;
            ConnectInfo     ci    = ConnectInfo.getInstance();
            ClientInfo      cInfo = ClientInfo.getInstance();

            data = CustomProtocolManager.MakeConnectRequestPacket();
            if (!SendingFunction(ci.tcpClient.Client, data))
            {
                return(false);
            }

            // 헤더 수신
            index = 0;
            data  = new byte[CustomProtocolManager.HEADER_SIZE];
            if (!ReceiveFunction(ci.tcpClient.Client, ref data, ref index, CustomProtocolManager.HEADER_SIZE))
            {
                return(false);
            }

            // 수신된 헤더 확인
            CustomProtocolManager.Header header = CustomProtocolManager.ParseHeader(ref data);

            // 데이터 수신
            index = 0;
            data  = new byte[header.size];
            if (!ReceiveFunction(ci.tcpClient.Client, ref data, ref index, (int)header.size))
            {
                return(false);
            }


            CustomProtocolManager.ParseClientReqInfoPacket(data, 0, (UInt32)data.Length, out serverName, out parameters, out reqInfos);
            ci.ServerName        = serverName;
            ci.securityParameter = parameters;

            // 필요 게임들이 존재하는지 확인


            DirectoryInfo di = new DirectoryInfo(ClientInfo.GAMEDATA_PATH);
            FileStream    fs;
            XmlSerializer xs = new XmlSerializer(typeof(GameInfo));
            GameInfo      registry;

            foreach (DirectoryInfo sdi in di.GetDirectories())
            {
                foreach (FileInfo fi in sdi.GetFiles())
                {
                    if (!fi.Extension.Equals(".info"))
                    {
                        continue;
                    }

                    fs = fi.OpenRead();

                    registry = (GameInfo)xs.Deserialize(fs);

                    for (int i = 0; i < reqInfos.Count; ++i)
                    {
                        if (GameInfo.IsSameInfo(reqInfos[i], registry))
                        {
                            cInfo.gameRegistries.Add(new GameRegistry {
                                gameInfo = registry, folderPath = fi.DirectoryName
                            });
                            reqInfos.RemoveAt(i);
                        }
                    }

                    fs.Close();
                }
            }

            // 필요 정보가 남아있으면 필요한 게임이 없으므로 서버 이용 불가
            if (reqInfos.Count != 0)
            {
                string msg;

                foreach (GameInfo gi in reqInfos)
                {
                    msg = "이 서버에 접속하기 위해서는 다음의 게임이 필요합니다."
                          + "\n게임명: " + gi.name
                          + "\n버전: " + gi.gameVersion
                          + "\n제작자: " + gi.producer;

                    MessageBox.Show(msg, "파일 누락");
                }
                return(false);
            }

            return(true);
        }
コード例 #27
0
        /*
         * 1. 현재 BeginReceive는 새로운 스레드를 만들어서 콜백을 처리하고있다.
         * */


        /*
         * 현재 수신 알고리즘 요약:
         * 1. 헤더를 먼저 해석하기 위해 헤더 크기만큼 무조건 받는다. => 비동기로 이 크기만큼 받도록 하나, 그것은 최대값이다.
         * 2. 헤더 크기에서 데이터 크기를 뽑아 Task 클래스를 이용한 새 스레드에서 데이터 크기만큼 읽게 한다.
         * 3. 온전한 바이트로 만들고 헤더에서 얻은 형식 정보를 이용해 해당 문장을 해석한다.
         * 4. 원본 스레드에서 다시 비동기 수신을 진행하라고 명령한다.
         * */

        #region 수신계
        /// <summary>
        /// 메세지 수신이 일어나면 사용하는 콜백 함수입니다.
        /// </summary>
        /// <param name="ar">송신 정보를 담아 포장하는 인터페이스입니다.</param>
        public static void MessageReceiveCallback(IAsyncResult ar)
        {
            User user = (User)ar.AsyncState;

            CustomProtocolManager.Header header;
            byte[] receivedData;

            try
            {
                user.msgReadedLength += user.client.Client.EndReceive(ar);
                if (user.client.Connected == false)
                {
                    return;                                                   // 접속상태가 아니면 메세지를 그냥 버림
                }
                if (user.msgReadedLength < CustomProtocolManager.HEADER_SIZE) // 메세지가 헤더의 원본 크기만큼 안왔다면
                {
                    user.client.Client.BeginReceive(user.msgHeaderHolder, user.msgReadedLength, CustomProtocolManager.HEADER_SIZE - user.msgReadedLength,
                                                    0, MessageReceiveCallback, user);
                    return;
                }

                // 헤더의 원본 크기만큼 읽었거나 그 이상 읽은경우는 이 구역을 실행한다.
                user.msgReadedLength = 0; // 읽어온 메세지 길이량을 다시 초기화하여 사용할 수 있게 한다
                header = CustomProtocolManager.ParseHeader(ref user.msgHeaderHolder);

                int received = 0;
                receivedData = new byte[header.size];

                while (received < header.size) // 이 문장은 동기적으로 데이터만큼 메세지를 읽어오도록 한다. 허나 데이터 길이가 0일수 있으므로 do while은 쓸 수 없다
                {
                    received += user.client.Client.Receive(receivedData, received, (int)header.size - received, 0);
                }
            }
            catch { return; } // 동작에 오류가 있었다면 통신에 문제가 있는 것이므로 해당 소켓으로부터 수신을 그만둔다.

            switch (header.typeNumber)
            {
            case CustomProtocolManager.TypeNumber.MakeConnection:
                // 인증계 메세지는 인증해야할 클라이언트가 아니면 연결을 끊어버린다.
                if (user.Id != null)
                {
                    user.client.Client.Disconnect(false);
                }
                else
                {
                    MakeConnectionMsgHandleFunction(header, receivedData, ref user);
                }
                break;

            case CustomProtocolManager.TypeNumber.Authorization:
                // 인증계 메세지는 인증된 클라이언트가 아니면 연결을 끊어버린다.
                if (user.Id != CustomProtocolManager.AUTHORIZED_CLIENT_TEMP_NAME)
                {
                    user.client.Client.Disconnect(false);
                }
                else
                {
                    AuthorizeMsgHandleFunction(header, receivedData, ref user);
                }
                break;

            case CustomProtocolManager.TypeNumber.Chatting:
                if (user.Id == null)
                {
                    user.client.Client.Disconnect(false);
                }
                else
                {
                    ChattingHandleFunction(header, receivedData, ref user);
                }
                break;

            case CustomProtocolManager.TypeNumber.InfoReq:
                if (user.Id == null)
                {
                    user.client.Client.Disconnect(false);
                }
                else
                {
                    InfoTypeMsgHandleFunction(header, receivedData, ref user);
                }
                break;

            case CustomProtocolManager.TypeNumber.InfoChange:
                if (user.Id == null)
                {
                    user.client.Client.Disconnect(false);
                }
                else
                {
                    InfoChangeMsgHandleFunction(header, receivedData, ref user);
                }
                break;

            default: break;     // 어느쪽에도 속하지 않으면 처리하지 않음
            }

            // MEMO: 성능의 문제로 한 소켓당 수신처리는 한번씩만 수행하도록 빼놓았다.
            try
            {
                user.client.Client.BeginReceive(user.msgHeaderHolder, 0, CustomProtocolManager.HEADER_SIZE,
                                                0, MessageReceiveCallback, user);
            }
            catch (Exception e)
            {
                Console.WriteLine("ReceiveCallback: " + e.Message);
            }
        }
コード例 #28
0
        // 채널 변경 요청에 대한 처리
        private static void ChannelChangeRequestHandler(CustomProtocolManager.Header header, byte[] msg, User target)
        {
            ServerProperty sp    = ServerProperty.getInstance();
            int            index = CustomProtocolManager.ParseChannelEnterRequestPacket(msg, 0);

            byte[] packet;

            if (index < sp.channelsList.Count)
            {
                if (sp.channelsList[index].CanEnter)
                {
                    if (sp.channelsList[index].users.TryAdd(target.Nickname, target))
                    {
                        User user;

                        if (target.RoomID != null)
                        {
                            if (target.RoomID.Equals(target.Nickname))
                            {
                                foreach (KeyValuePair <string, RoomMember> u in sp.channelsList[target.ChannelNumber].rooms[target.RoomID].members)
                                {
                                    SendToUser(
                                        sp.channelsList[target.ChannelNumber].users[u.Value.Nickname],
                                        CustomProtocolManager.MakeRoomResponsePacket()
                                        );
                                }
                                Room dummy;
                                sp.channelsList[target.ChannelNumber].rooms.TryRemove(target.RoomID, out dummy);
                            }
                            else
                            {
                                RoomMember dummy;
                                sp.channelsList[target.ChannelNumber].rooms[target.RoomID].members.TryRemove(target.Nickname, out dummy);
                            }
                        }

                        if (target.ChannelNumber != -1)
                        {
                            sp.channelsList[target.ChannelNumber].users.TryRemove(target.Nickname, out user);
                        }

                        target.RoomID        = null;
                        target.ChannelNumber = index;
                        packet = CustomProtocolManager.MakeChannelEnterResultPacket(CustomProtocolManager.GenericResponseType.Acknowledge);
                    }
                    else
                    {
                        packet = CustomProtocolManager.MakeChannelEnterResultPacket(CustomProtocolManager.GenericResponseType.Denied);
                    }
                }
                else
                {
                    packet = CustomProtocolManager.MakeChannelEnterResultPacket(CustomProtocolManager.GenericResponseType.Denied);
                }
            }
            else
            {
                packet = CustomProtocolManager.MakeChannelEnterResultPacket(CustomProtocolManager.GenericResponseType.Denied);
            }

            SendToUser(target, packet);
        }
コード例 #29
0
        /// <summary>
        /// 비동기 수신 메서드로부터 반응이오면 실행되는 콜백 함수입니다.
        /// 해당 콜백 함수는 MainFrame에서 사용되어야 합니다.
        /// </summary>
        /// <param name="ar">송신정보를 담아 생성되는 인터페이스 객체입니다.</param>
        public static void MainFrameMessageReceiveCallback(IAsyncResult ar)
        {
            #region 메세지 수신
            ConnectInfo ci = (ConnectInfo)ar.AsyncState;
            CustomProtocolManager.Header header;
            byte[] receivedData;

            try
            {
                ci.recvHeaderReaded += ci.tcpClient.Client.EndReceive(ar);

                if (ci.tcpClient.Connected == false)
                {
                    throw new Exception();                                   // 연결이 끊기면 메세지를 버리라고 알림
                }
                if (ci.recvHeaderReaded < CustomProtocolManager.HEADER_SIZE) // 메세지가 헤더의 원본 크기만큼 안왔다면 비동기적으로 더 수신하라고 명령한다
                {
                    ci.tcpClient.Client.BeginReceive(ci.recvHeaderBuffer, ci.recvHeaderReaded, CustomProtocolManager.HEADER_SIZE - ci.recvHeaderReaded,
                                                     0, MainFrameMessageReceiveCallback, ci);
                    return;
                }

                // 헤더의 원본 크기만큼 읽었거나 그 이상 읽은경우는 이 구역을 실행한다.
                header = CustomProtocolManager.ParseHeader(ref ci.recvHeaderBuffer);

                int received = 0;
                receivedData = new byte[header.size];

                if (!ReceiveFunction(ci.tcpClient.Client, ref receivedData, ref received, (int)header.size))
                {
                    throw new Exception();// 동기 수신에 실패하면 연결에 문제가 있으므로 예외처리
                }
                // 서버랑 다르게 처리하기 전에 비동기 수신 이벤트를 새로 등록한다.
                ci.recvHeaderReaded = 0; // 인덱스 초기화
            }
            catch (Exception e)
            { // 동작에 오류가 있었다면 통신에 문제가 있는 것이므로 프로그램을 재시작한다.
                Console.WriteLine("MainFrameMessageReceiveCallback: " + e.Message);

                MessageBox.Show("서버와의 통신에 이상이 생겨 접속이 끊겼습니다." +
                                "\n본 시스템의 네트워크에 이상이 없다면 " +
                                "서버가 오프라인이 되었을 가능성이 높습니다.", "통신 오류", MessageBoxButtons.OK, MessageBoxIcon.Error);

                Application.Exit();
                return;
            }
            #endregion
            #region 메세지 처리
            switch (header.typeNumber)
            {
            case CustomProtocolManager.TypeNumber.Chatting:
                ChattingHandleFunction(header, receivedData);
                break;

            case CustomProtocolManager.TypeNumber.ServerMessage:
                ServerMessageHandleFunction(receivedData);
                break;

            case CustomProtocolManager.TypeNumber.InfoReq:
                InfoTypeMsgHandleFunction(header, receivedData);
                break;

            case CustomProtocolManager.TypeNumber.InfoChange:
                InfoChangeMsgHandleFunction(header, receivedData);
                break;

            // 미사용 메세지 처리 구간
            case CustomProtocolManager.TypeNumber.MakeConnection: // 기초정보 제공은 앞선 폼에서 모두 사용한다
            case CustomProtocolManager.TypeNumber.Authorization:  // 인증방식은 로그인과 회원가입에서 모두 처리하는 방식이다
            default: break;                                       // 어느쪽에도 속하지 않으면 메세지를 버림
            }

            #endregion

            try
            {
                ci.tcpClient.Client.BeginReceive(ci.recvHeaderBuffer, 0, CustomProtocolManager.HEADER_SIZE, 0, MainFrameMessageReceiveCallback, ci);
            }
            catch (Exception e)
            {
                Console.WriteLine("MainFrameMessageReceiveCallback: " + e.Message);

                MessageBox.Show("서버와의 통신에 이상이 생겨 접속이 끊겼습니다." +
                                "\n본 시스템의 네트워크에 이상이 없다면 " +
                                "서버가 오프라인이 되었을 가능성이 높습니다.", "통신 오류", MessageBoxButtons.OK, MessageBoxIcon.Error);

                Application.Exit();
                return;
            }
        }
コード例 #30
0
        // 채팅 메세지 처리
        private static void ChattingHandleFunction(CustomProtocolManager.Header header, byte[] msg)
        {
            string parsedMsg = CustomProtocolManager.ParseGeneralChatting(msg, 0, (int)header.size);

            ClientInfo.getInstance().mainClientFrame.ChatWriter(parsedMsg, (int)header.optNumber);
        }