/// <summary> /// 서버에게 패킷을 보냅니다. /// 보내는 작업이 이미 동작중이면 작업큐에 메세지를 하나 더 얹습니다. /// </summary> /// <param name="packet">보내고자 하는 패킷입니다.</param> /// <param name="waitForThis">동기적으로 기다릴 것인지 결정하는 인자입니다. /// 기본값은 false 입니다.</param> /// 메세지를 보내라고 명령하는 함수. 이 함수는 위의 두 함수와 결합하여 사용한다. public static void SendToServer(byte[] packet, bool waitForThis = false) { ConnectInfo ci = ConnectInfo.getInstance(); ci.sendMsgQueue.Enqueue(packet); if (ci.sendTask == null) { ci.sendTask = new Task(StartSendingQueue); if (waitForThis) { ci.sendTask.RunSynchronously(); } else { ci.sendTask.Start(); } } else if (ci.sendTask.IsCompleted) { ci.sendTask = new Task(StartSendingQueue); if (waitForThis) { ci.sendTask.RunSynchronously(); } else { ci.sendTask.Start(); } } else if (waitForThis) { ci.sendTask.Wait(); } }
///////////////////////////// 이벤트 영역 ///////////////////////////// private void MainFrame_Load(object sender, EventArgs e) { ci = ConnectInfo.getInstance(); ci.tcpClient.Client.BeginReceive(ci.recvHeaderBuffer, ci.recvHeaderReaded, CustomProtocolManager.HEADER_SIZE, 0, MessageHandler.MainFrameMessageReceiveCallback, ci); if (!ChangeChannel()) // 처음에 채널 선택은 무조건 해야한다. { Application.Exit(); this.Close(); return; } timer_UserListRefresh.Start(); }
// 확인시 로직 private void Confirm() { if (btn_JoinNameCheck.Enabled == true) { MessageBox.Show("ID 중복 여부를 확인해주십시오.", "절차 안내", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); return; } if (btn_JoinNicknameCheck.Enabled == true) { MessageBox.Show("Nickname 중복 여부를 확인해주십시오.", "절차 안내", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); return; } JoinData data = new JoinData() { user_id = txt_JoinName.Text, user_password = txt_JoinPassword.Text, user_email = txt_JoinEmail.Text, nickname = txt_JoinNickname.Text, user_gender = rb_JoinWoman.Checked }; if (!MessageHandler.MakeAccount(data)) { if (!ConnectInfo.getInstance().tcpClient.Client.Connected) { MessageBox.Show("서버와 연결이 끊어졌습니다. 연결상태를 확인하십시오.\n연결상태에 문제가 없다면 서버가 오프라인이 되었을 가능성이 있습니다." , "연결 오류", MessageBoxButtons.OK, MessageBoxIcon.Error); Application.Exit(); return; } MessageBox.Show("계정을 생성하지 못했습니다. \n절차상에 문제가 생겼거나 누군가가 먼저 ID나 닉네임을 선점했을 가능성이 있습니다.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } MessageBox.Show("계정 생성에 성공하였습니다. 생성하신 계정으로 로그인해주십시오!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); id = txt_JoinName.Text; pwd = txt_JoinPassword.Text; DialogResult = DialogResult.OK; this.Close(); }
/// <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); }
/// <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); }
/// <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); }
/// <summary> /// 송신을 시작하라고 명령하는 함수입니다. /// 현재 송신 기능은 보내야할 메세지를 작업형태로 만들고 '공존 큐'에 넣어서 관리하고 있기 때문에 사용합니다. /// 이 함수는 내부 로직에 의해 동기적으로 송신하므로 Task와 조합하여 사용해야합니다. /// </summary> private async static void StartSendingQueue() { byte[] currentMessage; ConnectInfo ci = ConnectInfo.getInstance(); try // 작업을 진행하는 서버가 접속종료를 해서 오류가 날 경우가 있다. // 그리고 다른 함수 절차에 따라 프로그램이 종료되려고 할때 이 정보가 말소 될 가능성이 있다. // 이때 말소된 정보에 접근하려하면 프로그램이 죽을 것이다. 이를 방지한다. { do { if (!ci.sendMsgQueue.TryDequeue(out currentMessage)) { // 꺼내오는데 실패하면 대기하고 재시도하게 한다. await Task.Delay(ClientInfo.getInstance().sleepTime); continue; } SendingFunction(ci.tcpClient.Client, currentMessage); } while (ci.sendMsgQueue.Count > 0); } catch { } }
/// <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); }
public ConnectForm() { InitializeComponent(); ci = ConnectInfo.getInstance(); }
public LoginForm() { InitializeComponent(); ci = ConnectInfo.getInstance(); txt_ServerName.Text = ci.ServerName; }