static void Main(string[] args) { var print = new Printer(); var listener = new TcpListener(IPAddress.Any, 8039); listener.Start(); print.Printline("서버가 8039 포트에서 클라이언트 대기"); new Task(async() => { while (true) { var serverClient = await listener.AcceptTcpClientAsync(); var socket = new GameSocket(); socket.printHelper = print; Receivers.RegisterReceivers(socket); socket.AttachNetworkStream(serverClient.GetStream(), () => { try { ConnectedClient.UnregisterLogin(socket); serverClient.Close(); } catch { } }); } }).Start(); while (true) { //코더님, 역활이 없는 메인 스레드는 뭘 할수 있죠? //너는 쓸모가 없다, 팝콘이나 가져와라 메인 스레드 Thread.Sleep(int.MaxValue); } }
/// <summary> /// 저장되어 있는 게임 소켓을 반환합니다 /// </summary> /// <param name="createIfMissing">참일시 소켓이 없는경우 서버와 연결합니다</param> /// <returns></returns> public async Task <GameSocket> GetGameSocketAsync(bool createIfMissing = true, bool loginIfMissing = true) { while (SocketInCreate) { await Task.Delay(1); } if (gameSocket == null && createIfMissing) { SocketInCreate = true; tcpClient = new TcpClient(); gameSocket = new GameSocket(); gameSocket.printHelper = new Printer(); var handshakeCI = ConnectCanvas.Instance.CreateConnectInformation("서버에 연결", async(listener) => { try { await tcpClient.ConnectAsync(serverIP, serverPort); gameSocket.AttachNetworkStream(tcpClient.GetStream()); listener.OnFinish(); } catch (Exception ex) { listener.OnError(ex.Message); } }, null, -1) .StartAfter(ConnectCanvas.Instance.CreateConnectInformation("연결을 암호화", (receiver) => { gameSocket.HandshakeAsync(receiver); if (!loginIfMissing) { SocketInCreate = false; } }, null, autoStart: false)); if (loginIfMissing) { var account = Consts.GetAccountFromFile(); await handshakeCI.StartAfter(ConnectCanvas.Instance.CreateConnectInformation("로그인", (listener) => { if (account == null) { throw new Exception("계정이 없음"); } gameSocket.LoginAccountAsync(account.Id, account.AuthToken, listener); }, null, autoStart: false)) .StartAfter(ConnectCanvas.Instance.CreateConnectInformation("데이터를 다시 가져오는중", (listener) => { gameSocket.FetchDataAsync(listener); }, new FinishListener <FetchData>((data) => { DataManager.Instance.ReadFetchData(data); SocketInCreate = false; }, (message) => { }) )).WaitAsync(); } else { await handshakeCI.WaitAsync(); } } return(gameSocket); }
protected override void TestInternal() { var printer = new Printer(); #region Make Connection var listener = new TcpListener(IPAddress.Loopback, 8039); listener.Start(); var serverTask = listener.AcceptTcpClientAsync(); var clientTcp = new TcpClient(); var clientTask = clientTcp.ConnectAsync(IPAddress.Loopback, 8039); Console.WriteLine("Waiting for Connect..."); Task.WaitAll(serverTask, clientTask); Console.WriteLine("Connected! Wrapping with GameSocket"); var server = new GameSocket(); server.AttachNetworkStream(serverTask.GetAwaiter().GetResult().GetStream()); var client = new GameSocket(); client.AttachNetworkStream(clientTcp.GetStream()); Receivers.RegisterReceivers(server); server.SendPingAsync(); client.SendPingAsync(); WaitForFlag(() => { return(server.LastPongTime == -1); }, "서버가 클라이언트의 핑을 기다리는중... {0}"); WaitForFlag(() => { return(client.LastPongTime == -1); }, "클라이언트가 서버의 핑을 기다리는중... {0}"); Console.WriteLine("서로 핑을 주고 받았습니다!"); #endregion #region Alive Checker - No Response at all (half-open tcp connection) Console.WriteLine("Alive Checker - No Response at all (half-open tcp connection)"); var aliveCheckServerTask = listener.AcceptTcpClientAsync(); var aliveCheckClient = new TcpClient(); var aliveCheckClientTask = aliveCheckClient.ConnectAsync(IPAddress.Loopback, 8039); Task.WaitAll(aliveCheckClientTask, aliveCheckServerTask); var isClosed = false; var aliveCheckServerSocket = new GameSocket(); aliveCheckServerSocket.printHelper = printer; aliveCheckServerSocket.AttachNetworkStream(aliveCheckServerTask.GetAwaiter().GetResult().GetStream(), () => { isClosed = true; }); aliveCheckServerSocket.LastReceiveTime = DateTimeOffset.Now.ToUnixTimeMilliseconds() - 30000; Thread.Sleep(2000); aliveCheckServerSocket.LastReceiveTime = DateTimeOffset.Now.ToUnixTimeMilliseconds() - 60000; Thread.Sleep(2000); Assert(isClosed, true); aliveCheckClient.Close(); Console.WriteLine("Alive Checker - No Response at all (half-open tcp connection) is PASS"); #endregion #region Alive Checker - Client Closed Connection Console.WriteLine("Alive Checker - Client Closed Connection"); aliveCheckServerTask = listener.AcceptTcpClientAsync(); aliveCheckClient = new TcpClient(); aliveCheckClientTask = aliveCheckClient.ConnectAsync(IPAddress.Loopback, 8039); Task.WaitAll(aliveCheckClientTask, aliveCheckServerTask); isClosed = false; aliveCheckServerSocket = new GameSocket(); aliveCheckServerSocket.printHelper = printer; aliveCheckServerSocket.AttachNetworkStream(aliveCheckServerTask.GetAwaiter().GetResult().GetStream(), () => { isClosed = true; }); aliveCheckClient.Close(); aliveCheckServerSocket.LastReceiveTime = DateTimeOffset.Now.ToUnixTimeMilliseconds() - 30000; Thread.Sleep(2000); aliveCheckServerSocket.LastReceiveTime = DateTimeOffset.Now.ToUnixTimeMilliseconds() - 60000; Thread.Sleep(2000); Assert(isClosed, true); Console.WriteLine("Alive Checker - Client Closed Connection is PASS"); #endregion #region Handshake Console.WriteLine("암호화를 활성화 합니다"); var handshake = new HandshakePacket(); handshake.SendPacketAsync(client, null); WaitForFlag(() => { return(client.encryptHelper.UseAES); }, "연결의 암호화를 기다리는중... {0}"); var random = new Random(); server.registerRequestReceiver(new MessageReceiver()); server.registerRequestReceiver(new DevReceiver()); var messageFlag = new FlagReceiver(); var devFlag = new FlagReceiver(); var messageBuffer = new byte[1024 * 16]; random.NextBytes(messageBuffer); client.SendRequestAsync("message", messageBuffer, messageFlag); client.SendRequestAsync("dev", new byte[] { 0x0 }, devFlag); WaitForFlag(() => { return(messageFlag.IsReceived); }, "클라이언트가 랜덤 바이트 테스트의 응답을 기다리는중... {0}"); WaitForFlag(() => { return(devFlag.IsReceived); }, "클라이언트가 고정 메시지 테스트의 응답을 기다리는중... {0}"); Console.WriteLine("클라이언트가 응답을 수신함"); Assert(messageFlag.ReceivedData, messageBuffer); Assert(devFlag.ReceivedData, needMoreTime); Console.WriteLine("요청을 검증했습니다. 정상입니다."); #endregion #region Login Packet var authToken = new byte[128]; var rnd = new RNGCryptoServiceProvider(); rnd.GetBytes(authToken); string failMessage = null; Action throwIfFail = new Action(() => { if (failMessage != null) { throw new Exception(failMessage); } }); Account generatedAccount = null; var generateAccountPacket = new GenerateAccountPacket(); generateAccountPacket.SendPacketAsync(client, authToken, new FinishListener <Account>((account) => { generatedAccount = account; }, (message) => { failMessage = message; })); WaitForFlag(() => { return(generatedAccount != null || failMessage != null); }, "클라이언트가 서버의 계정 생성을 기다리는중... {0}"); throwIfFail(); var loginAccount = new LoginAccountPacket(); var badLoginPass = false; //Bad Token Test loginAccount.SendPacketAsync(client, generatedAccount.Id, new byte[128], new FinishListener(() => { failMessage = "클라이언트가 틀린 토큰으로 로그인을 성공했습니다"; }, (message) => { badLoginPass = true; })); WaitForFlag(() => { return(badLoginPass || failMessage != null); }, "클라이언트가 틀린 토큰으로 로그인 시도중... {0}"); throwIfFail(); var goodLoginPass = false; loginAccount.SendPacketAsync(client, generatedAccount.Id, authToken, new FinishListener(() => { goodLoginPass = true; }, (message) => { failMessage = message; })); WaitForFlag(() => { return(goodLoginPass || failMessage != null); }, "클라이언트가 정상 토큰으로 로그인 시도중... {0}"); throwIfFail(); var fetchDataPacket = new FetchDataPacket(); FetchData data = null; fetchDataPacket.SendPacketAsync(client, new FinishListener <FetchData>((fetchData) => { data = fetchData; }, (message) => { failMessage = message; })); WaitForFlag(() => { return(data != null || failMessage != null); }, "클라이언트가 시작에 필요한 정보를 가져오는중... {0}"); throwIfFail(); #endregion #region Resource Packet var resourcePacket = new GetResourceStatusPacket(); bool resourceReceived = false; resourcePacket.SendPacketAsync(client, new FinishListener <Resource>((resource) => { Console.WriteLine($"자원정보 수신함(Mo/Fo/El/Ti): {resource.Money}/{resource.Food}/{resource.Electric}/{resource.Time}"); resourceReceived = true; }, (message) => { failMessage = message; })); WaitForFlag(() => { return(resourceReceived || failMessage != null); }, "자원 정보를 서버로부터 받는중... {0}"); throwIfFail(); listener.Stop(); #endregion }