using Island.StandardLib.Exceptions; using Island.StandardLib.Storage; using System; using System.Net; using System.Net.Sockets; using System.Threading; namespace Island.StandardLib { public abstract class ConnectionClient { public string ServerAddress { get; private set; } public int ServerPort { get; private set; } public int MaxBitSize { get; private set; } public bool DebugMode { get; set; } public uint ClientVersion { get; private set; } public ConnectionClient(string addr, int port, uint version = 1, bool debug = false, int maxbitsz = 524288) { ServerAddress = addr; ServerPort = port; ClientVersion = version; MaxBitSize = maxbitsz; DebugMode = debug; } public ConnectObjectFromClient CommandSendPool; public Socket ClientSocket; public bool IsConnected { get; private set; } Thread clientLoop; /// /// 自定义登录动作完成后调用此函数开启通信循环 /// public void KeepConnect() { if (clientLoop != null) if (clientLoop.IsAlive) throw new PlayerSocketFatalException("client", PlayerSocketFatalExceptionType.InternalDuplicatePlayerThreadStart); clientLoop = new Thread(ClientLoop) { IsBackground = true }; clientLoop.Start(); //KeepConnect()(default); } //public Func KeepConnect() where TIn : struct where TOut : class //{ // return t => // { // KeepConnect(); // Func func = () => // { // return default(TOut); // }; // }; //} public LoginResult ConnectAsLogin(RequestType request) where RequestType : ILoginOrRegisterRequest, IStorable, new() { try { request.ClientVersion = ClientVersion; request.IsLogin = true; IPAddress[] addr = Dns.GetHostAddresses(ServerAddress); ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); ClientSocket.Connect(addr, ServerPort); ClientSocket.SendOnce(request); LoginCallback lcb = ClientSocket.ReceiveOnce(512); if (lcb.Success) { KeepConnect(); } else { try { ClientSocket.Close(); ClientSocket.Dispose(); } catch { } } return lcb.Code; } catch (Exception) { try { ClientSocket?.Close(); ClientSocket?.Dispose(); } catch { } return LoginResult.ConnectionError; } } public RegisterData ConnectAsRegister(RequestType request) where RequestType : ILoginOrRegisterRequest, IStorable, new() { try { request.IsLogin = false; IPAddress[] addr = Dns.GetHostAddresses(ServerAddress); Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); sock.Connect(addr, ServerPort); sock.SendOnce(request); RegisterCallback rcb = sock.ReceiveOnce(512); try { sock.Close(); sock.Dispose(); } catch { } if (rcb.Success) return new RegisterData(RegisterResult.Success, rcb.Username); else return new RegisterData((RegisterResult)rcb.Username, -1); } catch { return new RegisterData(RegisterResult.ConnectionError, -1); } } public void ConnectAsRegister(RequestType request, out RegisterCallback rcb) where RequestType : ILoginOrRegisterRequest, IStorable, new() { try { request.IsLogin = false; IPAddress[] addr = Dns.GetHostAddresses(ServerAddress); Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); sock.Connect(addr, ServerPort); sock.SendOnce(request); rcb = sock.ReceiveOnce(512); try { sock.Close(); sock.Dispose(); } catch { } } catch { rcb = null; } } public T ConnectManual(byte[] bSend) where T : IStorable, new() { try { IPAddress[] addr = Dns.GetHostAddresses(ServerAddress); Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); sock.Connect(addr, ServerPort); sock.SendOnce(bSend); T ret = sock.ReceiveOnce(2048); try { sock.Close(); sock.Dispose(); } catch { } return ret; } catch { return default; } } //public LoginResult ConnectAsLogin(int userName, string password) //{ // try // { // LoginOrRegisterRequest request = new LoginOrRegisterRequest(userName, password, ClientVersion); // request.IsLogin = true; // IPAddress[] addr = Dns.GetHostAddresses(ServerAddress); // ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // ClientSocket.Connect(addr, ServerPort); // ClientSocket.SendOnce(request); // LoginCallback lcb = ClientSocket.ReceiveOnce(512); // if (lcb.Success) // { // Thread clientLoop = new Thread(ClientLoop); // clientLoop.IsBackground = true; // clientLoop.Start(); // //Thread watchLoop = new Thread(WatcherLoop); // //watchLoop.IsBackground = true; // //watchLoop.Start(); // } // else // { // try // { // ClientSocket.Close(); // ClientSocket.Dispose(); // } // catch { } // } // return lcb.Code; // } // catch (Exception e) // { // try // { // ClientSocket?.Close(); // ClientSocket?.Dispose(); // } // catch { } // return LoginResult.ConnectionError; // } //} //public RegisterData ConnectAsRegister(string nickname, string password) //{ // try // { // LoginOrRegisterRequest request = new LoginOrRegisterRequest(0, password, ClientVersion); // request.IsRegister = true; // request.Nickname = nickname; // IPAddress[] addr = Dns.GetHostAddresses(ServerAddress); // Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // sock.Connect(addr, ServerPort); // sock.SendOnce(request); // RegisterCallback rcb = sock.ReceiveOnce(512); // try // { // sock.Close(); // sock.Dispose(); // } // catch { } // if (rcb.Success) return new RegisterData(RegisterResult.Success, rcb.Username); // else return new RegisterData((RegisterResult)rcb.Username, -1); // } // catch // { // return new RegisterData(RegisterResult.ConnectionError, -1); // } //} //void WatcherLoop() //{ // while (true) // { // contFlag = false; // Thread.Sleep(5000); // if (!contFlag) // { // IsConnected = false; // OnConnectionBreaked(new Exception("Wait too long")); // } // } //} bool contFlag = true; public void Shutdown() => contFlag = false; public virtual void OnClientWillSendDataToServer(ConnectObjectFromServer serverData) { } void ClientLoop() { Exception endWith; CommandSendPool = new ConnectObjectFromClient(); IsConnected = true; OnConnectionBegin(); ClientSocket.SendTimeout = 5000; ClientSocket.ReceiveTimeout = 5000; while (true) { try { ConnectObjectFromServer serverData = ClientSocket.ReceiveOnce(MaxBitSize); if (!contFlag) throw new Exception("Shutdown flag enabled."); bool recvCmds, sendCmds; lock (CommandSendPool) { InnerCommandPass(serverData); OnClientWillSendDataToServer(serverData); ClientSocket.SendOnce(CommandSendPool); recvCmds = serverData.Commands.Count != 0; sendCmds = CommandSendPool.Commands.Count != 0; CommandSendPool.ClearCommands(); } if (DebugMode) { if (recvCmds && sendCmds) { Console.BackgroundColor = ConsoleColor.Red; Console.Write("x"); } else if (recvCmds) { Console.BackgroundColor = ConsoleColor.DarkBlue; Console.Write("-"); } else if (sendCmds) { Console.BackgroundColor = ConsoleColor.DarkGreen; Console.Write("+"); } else { Console.BackgroundColor = ConsoleColor.Black; Console.Write("="); } } } catch (Exception e) { endWith = e; break; } } try { ClientSocket.Close(); ClientSocket.Dispose(); } catch { } IsConnected = false; BreakedException = endWith; OnConnectionBreaked(endWith); } public Exception BreakedException; void InnerCommandPass(ConnectObjectFromServer serverData) { for (int i = 0; i < serverData.Commands.Length; i++) { ConnectCommand command = serverData.Commands[i]; PassCommand(command); } } protected abstract void PassCommand(ConnectCommand command); protected virtual void OnConnectionBegin() { } protected virtual void OnConnectionBreaked(Exception reason) { } } public struct RegisterData { public RegisterData(RegisterResult r, int u) { result = r; uid = u; } public RegisterResult result; public int uid; } }